diff options
Diffstat (limited to 'sal/osl')
135 files changed, 66390 insertions, 0 deletions
diff --git a/sal/osl/all/debugbase.cxx b/sal/osl/all/debugbase.cxx new file mode 100644 index 000000000000..10679cb45ccb --- /dev/null +++ b/sal/osl/all/debugbase.cxx @@ -0,0 +1,161 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "rtl/strbuf.hxx" +#include "rtl/string.hxx" +#include "rtl/ustring.hxx" +#include "osl/process.h" +#include "osl/diagnose.hxx" +#include "boost/bind.hpp" +#include <vector> + +// define own ones, independent of OSL_DEBUG_LEVEL: +#define DEBUGBASE_ENSURE_(c, f, l, m) \ + do \ + { \ + if (!(c) && _OSL_GLOBAL osl_assertFailedLine(f, l, m)) \ + _OSL_GLOBAL osl_breakDebug(); \ + } while (0) +#define DEBUGBASE_ENSURE(c, m) DEBUGBASE_ENSURE_(c, OSL_THIS_FILE, __LINE__, m) + +namespace { + +typedef std::vector<rtl::OString, rtl::Allocator<rtl::OString> > OStringVec; + +struct StaticDebugBaseAddressFilter + : rtl::StaticWithInit<OStringVec const, StaticDebugBaseAddressFilter> { + OStringVec const operator()() const { + OStringVec vec; + rtl_uString * pStr = 0; + rtl::OUString const name( + RTL_CONSTASCII_USTRINGPARAM("OSL_DEBUGBASE_STORE_ADDRESSES") ); + if (osl_getEnvironment( name.pData, &pStr ) == osl_Process_E_None) { + rtl::OUString const str(pStr); + rtl_uString_release(pStr); + sal_Int32 nIndex = 0; + do { + vec.push_back( rtl::OUStringToOString( + str.getToken( 0, ';', nIndex ), + RTL_TEXTENCODING_ASCII_US ) ); + } + while (nIndex >= 0); + } + return vec; + } +}; + +inline bool isSubStr( char const* pStr, rtl::OString const& subStr ) +{ + return rtl_str_indexOfStr( pStr, subStr.getStr() ) >= 0; +} + +struct DebugBaseMutex : ::rtl::Static<osl::Mutex, DebugBaseMutex> {}; + +} // anon namespace + +extern "C" { + +osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex() + SAL_THROW_EXTERN_C() +{ + return DebugBaseMutex::get(); +} + +bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses( char const* pName ) + SAL_THROW_EXTERN_C() +{ + OStringVec const& rVec = StaticDebugBaseAddressFilter::get(); + if (rVec.empty()) + return false; + // check for "all": + rtl::OString const& rFirst = rVec[0]; + if (rtl_str_compare_WithLength( rFirst.getStr(), rFirst.getLength(), + RTL_CONSTASCII_STRINGPARAM("all") ) == 0) + return true; + OStringVec::const_iterator const iEnd( rVec.end() ); + return std::find_if( rVec.begin(), iEnd, + boost::bind( &isSubStr, pName, _1 ) ) != iEnd; +} + +bool SAL_CALL osl_detail_ObjectRegistry_checkObjectCount( + osl::detail::ObjectRegistryData const& rData, std::size_t nExpected ) + SAL_THROW_EXTERN_C() +{ + std::size_t nSize; + if (rData.m_bStoreAddresses) + nSize = rData.m_addresses.size(); + else + nSize = static_cast<std::size_t>(rData.m_nCount); + + bool const bRet = (nSize == nExpected); + if (! bRet) { + rtl::OStringBuffer buf; + buf.append( RTL_CONSTASCII_STRINGPARAM("unexpected number of ") ); + buf.append( rData.m_pName ); + buf.append( RTL_CONSTASCII_STRINGPARAM(": ") ); + buf.append( static_cast<sal_Int64>(nSize) ); + DEBUGBASE_ENSURE( false, buf.makeStringAndClear().getStr() ); + } + return bRet; +} + +void SAL_CALL osl_detail_ObjectRegistry_registerObject( + osl::detail::ObjectRegistryData & rData, void const* pObj ) + SAL_THROW_EXTERN_C() +{ + if (rData.m_bStoreAddresses) { + osl::MutexGuard const guard( osl_detail_ObjectRegistry_getMutex() ); + std::pair<osl::detail::VoidPointerSet::iterator, bool> const insertion( + rData.m_addresses.insert(pObj) ); + DEBUGBASE_ENSURE( insertion.second, "### insertion failed!?" ); + static_cast<void>(insertion); + } + else { + osl_incrementInterlockedCount(&rData.m_nCount); + } +} + +void SAL_CALL osl_detail_ObjectRegistry_revokeObject( + osl::detail::ObjectRegistryData & rData, void const* pObj ) + SAL_THROW_EXTERN_C() +{ + if (rData.m_bStoreAddresses) { + osl::MutexGuard const guard( osl_detail_ObjectRegistry_getMutex() ); + std::size_t const n = rData.m_addresses.erase(pObj); + DEBUGBASE_ENSURE( n == 1, "erased more than 1 entry!?" ); + static_cast<void>(n); + } + else { + osl_decrementInterlockedCount(&rData.m_nCount); + } +} + +} // extern "C" + diff --git a/sal/osl/all/filepath.c b/sal/osl/all/filepath.c new file mode 100644 index 000000000000..e9461a538840 --- /dev/null +++ b/sal/osl/all/filepath.c @@ -0,0 +1,123 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <osl/file.h> +#include <rtl/ustring.h> + +static sal_uInt32 SAL_CALL osl_defCalcTextWidth( rtl_uString *ustrText ) +{ + return ustrText ? ustrText->length : 0; +} + + +oslFileError SAL_CALL osl_abbreviateSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrCompacted, sal_uInt32 uMaxWidth, oslCalcTextWidthFunc pfnCalcWidth ) +{ + oslFileError error = osl_File_E_None; + rtl_uString *ustrPath = NULL; + rtl_uString *ustrFile = NULL; + sal_uInt32 uPathWidth, uFileWidth; + + if ( !pfnCalcWidth ) + pfnCalcWidth = osl_defCalcTextWidth; + + { + sal_Int32 iLastSlash = rtl_ustr_lastIndexOfChar_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, SAL_PATHDELIMITER ); + + if ( iLastSlash >= 0 ) + { + rtl_uString_newFromStr_WithLength( &ustrPath, ustrSystemPath->buffer, iLastSlash ); + rtl_uString_newFromStr_WithLength( &ustrFile, &ustrSystemPath->buffer[iLastSlash], ustrSystemPath->length - iLastSlash ); + } + else + { + rtl_uString_new( &ustrPath ); + rtl_uString_newFromString( &ustrFile, ustrSystemPath ); + } + } + + uPathWidth = pfnCalcWidth( ustrPath ); + uFileWidth = pfnCalcWidth( ustrFile ); + + /* First abbreviate the directory component of the path */ + + while ( uPathWidth + uFileWidth > uMaxWidth ) + { + if ( ustrPath->length > 3 ) + { + ustrPath->length--; + ustrPath->buffer[ustrPath->length-3] = '.'; + ustrPath->buffer[ustrPath->length-2] = '.'; + ustrPath->buffer[ustrPath->length-1] = '.'; + ustrPath->buffer[ustrPath->length] = 0; + + uPathWidth = pfnCalcWidth( ustrPath ); + } + else + break; + } + + /* Now abbreviate file component */ + + while ( uPathWidth + uFileWidth > uMaxWidth ) + { + if ( ustrFile->length > 4 ) + { + ustrFile->length--; + ustrFile->buffer[ustrFile->length-3] = '.'; + ustrFile->buffer[ustrFile->length-2] = '.'; + ustrFile->buffer[ustrFile->length-1] = '.'; + ustrFile->buffer[ustrFile->length] = 0; + + uFileWidth = pfnCalcWidth( ustrFile ); + } + else + break; + } + + rtl_uString_newConcat( pustrCompacted, ustrPath, ustrFile ); + + /* Event now if path was compacted to ".../..." it can be to large */ + + uPathWidth += uFileWidth; + + while ( uPathWidth > uMaxWidth ) + { + (*pustrCompacted)->length--; + (*pustrCompacted)->buffer[(*pustrCompacted)->length] = 0; + uPathWidth = pfnCalcWidth( *pustrCompacted ); + } + + if ( ustrPath ) + rtl_uString_release( ustrPath ); + + if ( ustrFile ) + rtl_uString_release( ustrFile ); + + return error; +} + + diff --git a/sal/osl/all/loadmodulerelative.cxx b/sal/osl/all/loadmodulerelative.cxx new file mode 100644 index 000000000000..39bea770e8a1 --- /dev/null +++ b/sal/osl/all/loadmodulerelative.cxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "sal/config.h" + +#include <cstddef> + +#include "osl/diagnose.h" +#include "osl/module.h" +#include "osl/module.hxx" +#include "osl/thread.h" +#include "rtl/malformeduriexception.hxx" +#include "rtl/uri.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" + +extern "C" { + +oslModule SAL_CALL osl_loadModuleRelative( + oslGenericFunction const baseModule, rtl_uString * const relativePath, + sal_Int32 const mode) +{ + ::rtl::OUString base; + if (!::osl::Module::getUrlFromAddress(baseModule, base)) { + OSL_TRACE("osl::Module::getUrlFromAddress failed"); + return NULL; + } + ::rtl::OUString abs; + try { + abs = ::rtl::Uri::convertRelToAbs(base, relativePath); + } catch (::rtl::MalformedUriException & e) { + (void) e; // avoid warnings + OSL_TRACE( + "rtl::MalformedUriException <%s>", + rtl::OUStringToOString(e.getMessage(), osl_getThreadTextEncoding()). + getStr()); + //TODO: let some OSL_TRACE variant take care of text conversion? + return NULL; + } + return ::osl_loadModule(abs.pData, mode); +} + +} diff --git a/sal/osl/all/makefile.mk b/sal/osl/all/makefile.mk new file mode 100644 index 000000000000..0d105906effb --- /dev/null +++ b/sal/osl/all/makefile.mk @@ -0,0 +1,76 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=sal +TARGET=oslall +ENABLE_EXCEPTIONS=TRUE +USE_LDUMP2=TRUE + +PROJECTPCH4DLL=TRUE +PROJECTPCH=cont_pch +PROJECTPCHSOURCE=cont_pch + +MULTITHREAD_OBJ=TRUE + +.IF "$(GUI)" == "OS2" +STL_OS2_BUILDING=1 +.ENDIF + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +CFLAGS+= $(LFS_CFLAGS) +CXXFLAGS+= $(LFS_CFLAGS) + +# --- Files -------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/utility.obj\ + $(SLO)$/filepath.obj\ + $(SLO)$/debugbase.obj\ + $(SLO)$/loadmodulerelative.obj + +# $(SLO)$/readline.obj\ + +#.IF "$(UPDATER)"=="YES" +OBJFILES= \ + $(OBJ)$/utility.obj\ + $(OBJ)$/filepath.obj\ + $(OBJ)$/debugbase.obj\ + $(OBJ)$/loadmodulerelative.obj + +# $(OBJ)$/readline.obj\ +#.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + + diff --git a/sal/osl/all/utility.cxx b/sal/osl/all/utility.cxx new file mode 100755 index 000000000000..21c392ba1793 --- /dev/null +++ b/sal/osl/all/utility.cxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + + +#include "rtl/ustring.hxx" +#include "osl/time.h" +#include <stdio.h> + + +/* + * mfe : maybe it would be wishful to include initialization + * of the global timer in dllmain or _init directly. + * But noneoftheless this (should) work too. + */ +namespace osl +{ + +class OGlobalTimer +{ + +public: + + OGlobalTimer() { + getTime(); + } + + sal_uInt32 getTime() + { + return osl_getGlobalTimer(); + } + + +}; + +static OGlobalTimer aGlobalTimer; + +} + + +extern "C" +{ +void debug_ustring(rtl_uString* ustr) +{ + sal_Char* psz=0; + rtl_String* str=0; + + if ( ustr != 0 ) + { + rtl_uString2String( &str, + rtl_uString_getStr(ustr), + rtl_uString_getLength(ustr), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + + psz = rtl_string_getStr(str); + } + + fprintf(stderr,"'%s'\n",psz); + + if ( str != 0 ) + { + rtl_string_release(str); + } + + return; +} + +} + +void debug_oustring(rtl::OUString& ustr) +{ + + debug_ustring(ustr.pData); + + return; +} diff --git a/sal/osl/os2/conditn.c b/sal/osl/os2/conditn.c new file mode 100644 index 000000000000..9ad2459fd851 --- /dev/null +++ b/sal/osl/os2/conditn.c @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/conditn.h> +#include <osl/diagnose.h> +#include <osl/time.h> + + + +/* + under WIN32, we use the void* oslCondition + as a WIN32 HANDLE (which is also a 32-bit value) +*/ + +/*****************************************************************************/ +/* osl_createCondition */ +/*****************************************************************************/ +oslCondition SAL_CALL osl_createCondition() +{ + HEV hevCondition; + APIRET rc; + + rc = DosCreateEventSem( NULL, /* unnamed semaphore */ + &hevCondition, /* pointer to variable */ + /* for the sem-handle */ + DC_SEM_SHARED, /* shared semaphore */ + FALSE ); /* initial state is posted */ + + if( rc == NO_ERROR ) + return (oslCondition)hevCondition; + else + return NULL; +} + +/*****************************************************************************/ +/* osl_destroyCondition */ +/*****************************************************************************/ +void SAL_CALL osl_destroyCondition(oslCondition Condition) +{ + if( Condition ) + DosCloseEventSem( (HEV) Condition ); +} + +/*****************************************************************************/ +/* osl_setCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setCondition(oslCondition Condition) +{ + OSL_ASSERT(Condition); + + return DosPostEventSem((HEV)Condition) == NO_ERROR; +} + +/*****************************************************************************/ +/* osl_resetCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_resetCondition(oslCondition Condition) +{ + ULONG ulPostCount; + + OSL_ASSERT(Condition); + + return DosResetEventSem((HEV)Condition, &ulPostCount) == NO_ERROR; +} + +/*****************************************************************************/ +/* osl_waitCondition */ +/*****************************************************************************/ +oslConditionResult SAL_CALL osl_waitCondition(oslCondition Condition, const TimeValue * pTimeout ) +{ + long nTimeout; + APIRET rc; + OSL_ASSERT(Condition); + + if( pTimeout ) + nTimeout = pTimeout->Seconds * 1000 + pTimeout->Nanosec / 1000000; + else + nTimeout = SEM_INDEFINITE_WAIT; + + rc = DosWaitEventSem((HEV)Condition, nTimeout ); + if( rc == ERROR_TIMEOUT ) + return osl_cond_result_timeout; + if( rc != NO_ERROR ) + return osl_cond_result_error; + + return osl_cond_result_ok; +} + +/*****************************************************************************/ +/* osl_checkCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_checkCondition(oslCondition Condition) +{ + OSL_ASSERT(Condition); + + return( DosWaitEventSem((HEV)Condition, SEM_IMMEDIATE_RETURN) == NO_ERROR); +} + diff --git a/sal/osl/os2/debug.c b/sal/osl/os2/debug.c new file mode 100644 index 000000000000..f2d0f915f375 --- /dev/null +++ b/sal/osl/os2/debug.c @@ -0,0 +1,2152 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* + *@@sourcefile debug.c: + * this file contains debugging functions for the + * exception handlers in except.c. + * + * This code is capable of unwinding the stack from + * a given address and trying to get function names + * and source line numbers, either from the respective + * module's debug code (if present) or from a SYM file, + * which is searched for in the directory of the module + * or in ?:\OS2\PDPSI\PMDF\WARP4. + * + * This file incorporates code from the following: + * -- Marc Fiammante, John Currier, Kim Rasmussen, + * Anthony Cruise (EXCEPT3.ZIP package for a generic + * exception handling DLL, available at Hobbes). + * + * Usage: All OS/2 programs. + * + * Note: Version numbering in this file relates to XWorkplace version + * numbering. + * + *@@changed V0.9.0 [umoeller]: made some declarations C++-compatible + *@@changed V0.9.1 (2000-01-30) [umoeller]: greatly cleaned up this file + * + *@@header "helpers\debug.h" + */ + +/* + * This file Copyright (C) 1992-99 Ulrich M�ller, + * Kim Rasmussen, + * Marc Fiammante, + * John Currier, + * Anthony Cruise. + * This file is part of the "XWorkplace helpers" source package. + * + * 2009-06-15 published under LGPL3 with Ulrich M�ller permission. + * + */ + +//#define DEBUG_SYMDUMP // enable to dump sym file to log + +//YD commented, since we need unsigned char BYTE! +//#define OS2EMX_PLAIN_CHAR +//Also gcc char is signed, while most structures requires unsigned data! +//Raised limits for all fields! + + // this is needed for "os2emx.h"; if this is defined, + // emx will define PSZ as _signed_ char, otherwise + // as unsigned char + +#define INCL_DOSPROCESS +#define INCL_DOSMODULEMGR +#define INCL_DOSMISC +#define INCL_DOSERRORS +#include <os2.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define DONT_REPLACE_MALLOC +#include "helpers\setup.h" // code generation and debugging options + +#include "helpers\debug.h" +#include "helpers\dosh.h" + +#pragma hdrstop + +#include <fcntl.h> +#ifdef __EMX__ + #include <sys\types.h> // required for sys\stat.h; UM 99-10-22 +#endif +#include <sys\stat.h> +#include <share.h> +#include <io.h> + +#ifndef DWORD +#define DWORD unsigned long +#endif +#ifndef WORD +#define WORD unsigned short +#endif + +#pragma stack16(512) +#define HF_STDERR 2 + +/* + *@@category: Helpers\Control program helpers\Exceptions/debugging + * See except.c and debug.c. + */ + +/* ****************************************************************** + * + * Global variables + * + ********************************************************************/ + +// this specifies whether we're dealing with 32-bit code; +// this gets changed whenever 16-bit count is detected +static BOOL f32bit = TRUE; + +/* + * Global variables for Read32PmDebug: + * + */ + +ULONG func_ofs; +ULONG pubfunc_ofs; +//YD 17/07/06 c++ namespace can generate really long +//YD names, use a large buffer! +char func_name[16*1024]; +ULONG var_ofs = 0; + +struct { + BYTE name[128]; + ULONG stack_offset; + USHORT type_idx; +} autovar_def[1024]; + +#pragma pack(1) + +BYTE *type_name[] = +{ + "8 bit signed ", + "16 bit signed ", + "32 bit signed ", + "Unknown (0x83) ", + "8 bit unsigned ", + "16 bit unsigned ", + "32 bit unsigned ", + "Unknown (0x87) ", + "32 bit real ", + "64 bit real ", + "80 bit real ", + "Unknown (0x8B) ", + "64 bit complex ", + "128 bit complex ", + "160 bit complex ", + "Unknown (0x8F) ", + "8 bit boolean ", + "16 bit boolean ", + "32 bit boolean ", + "Unknown (0x93) ", + "8 bit character ", + "16 bit characters ", + "32 bit characters ", + "void ", + "15 bit unsigned ", + "24 bit unsigned ", + "31 bit unsigned ", + "Unknown (0x9B) ", + "Unknown (0x9C) ", + "Unknown (0x9D) ", + "Unknown (0x9E) ", + "Unknown (0x9F) ", + "near pointer to 8 bit signed ", + "near pointer to 16 bit signed ", + "near pointer to 32 bit signed ", + "Unknown (0xA3) ", + "near pointer to 8 bit unsigned ", + "near pointer to 16 bit unsigned ", + "near pointer to 32 bit unsigned ", + "Unknown (0xA7) ", + "near pointer to 32 bit real ", + "near pointer to 64 bit real ", + "near pointer to 80 bit real ", + "Unknown (0xAB) ", + "near pointer to 64 bit complex ", + "near pointer to 128 bit complex ", + "near pointer to 160 bit complex ", + "Unknown (0xAF) ", + "near pointer to 8 bit boolean ", + "near pointer to 16 bit boolean ", + "near pointer to 32 bit boolean ", + "Unknown (0xB3) ", + "near pointer to 8 bit character ", + "near pointer to 16 bit characters", + "near pointer to 32 bit characters", + "near pointer to void ", + "near pointer to 15 bit unsigned ", + "near pointer to 24 bit unsigned ", + "near pointer to 31 bit unsigned ", + "Unknown (0xBB) ", + "Unknown (0xBC) ", + "Unknown (0xBD) ", + "Unknown (0xBE) ", + "Unknown (0xBF) ", + "far pointer to 8 bit signed ", + "far pointer to 16 bit signed ", + "far pointer to 32 bit signed ", + "Unknown (0xC3) ", + "far pointer to 8 bit unsigned ", + "far pointer to 16 bit unsigned ", + "far pointer to 32 bit unsigned ", + "Unknown (0xC7) ", + "far pointer to 32 bit real ", + "far pointer to 64 bit real ", + "far pointer to 80 bit real ", + "Unknown (0xCB) ", + "far pointer to 64 bit complex ", + "far pointer to 128 bit complex ", + "far pointer to 160 bit complex ", + "Unknown (0xCF) ", + "far pointer to 8 bit boolean ", + "far pointer to 16 bit boolean ", + "far pointer to 32 bit boolean ", + "Unknown (0xD3) ", + "far pointer to 8 bit character ", + "far pointer to 16 bit characters ", + "far pointer to 32 bit characters ", + "far pointer to void ", + "far pointer to 15 bit unsigned ", + "far pointer to 24 bit unsigned ", + "far pointer to 31 bit unsigned ", +}; + +// Thanks to John Currier: +// Do not call 16 bit code in myHandler function to prevent call +// to __EDCThunkProlog and problems is guard page exception handling +// Also reduce the stack size to 1K for true 16 bit calls. +// 16 bit calls thunk will now only occur on fatal exceptions +#pragma stack16(1024) + +// ------------------------------------------------------------------ +// Last 8 bytes of 16:16 file when CODEVIEW debugging info is present +#pragma pack(1) +struct _eodbug +{ + unsigned short dbug; // 'NB' signature + unsigned short ver; // version + unsigned long dfaBase; // size of codeview info +} G_eodbug; + +#define DBUGSIG 0x424E +#define SSTMODULES 0x0101 +#define SSTPUBLICS 0x0102 +#define SSTTYPES 0x0103 +#define SSTSYMBOLS 0x0104 +#define SSTSRCLINES 0x0105 +#define SSTLIBRARIES 0x0106 +#define SSTSRCLINES2 0x0109 +#define SSTSRCLINES32 0x010B + +typedef struct _SYMBASE +{ + unsigned short dbug; // 'NB' signature + unsigned short ver; // version + unsigned long lfoDir; // file offset to dir entries +} SYMBASE; + +typedef struct _SSDIR +{ + unsigned short sst; // SubSection Type + unsigned short modindex; // Module index number + unsigned long lfoStart; // Start of section + unsigned short cb; // Size of section +} SSDIR; + +typedef struct _SSDIR32 +{ + unsigned short sst; // SubSection Type + unsigned short modindex; // Module index number + unsigned long lfoStart; // Start of section + unsigned long cb; // Size of section +} SSDIR32; + +typedef struct _SSMODULE +{ + unsigned short csBase; // code segment base + unsigned short csOff; // code segment offset + unsigned short csLen; // code segment length + unsigned short ovrNum; // overlay number + unsigned short indxSS; // Index into sstLib or 0 + unsigned short reserved; + BYTE csize; // size of prefix string +} SSMODULE; + +typedef struct _SSMOD32 +{ + unsigned short csBase; // code segment base + unsigned long csOff; // code segment offset + unsigned long csLen; // code segment length + unsigned long ovrNum; // overlay number + unsigned short indxSS; // Index into sstLib or 0 + unsigned long reserved; + BYTE csize; // size of prefix string +} SSMOD32; + +typedef struct _SSPUBLIC +{ + unsigned short offset; + unsigned short segment; + unsigned short type; + BYTE csize; +} SSPUBLIC; + +typedef struct _SSPUBLIC32 +{ + unsigned long offset; + unsigned short segment; + unsigned short type; + BYTE csize; +} SSPUBLIC32; + +typedef struct _SSLINEENTRY32 +{ + unsigned short LineNum; + unsigned short FileNum; + unsigned long Offset; +} SSLINEENTRY32; + +typedef struct _FIRSTLINEENTRY32 +{ + unsigned short LineNum; + unsigned char entry_type; + unsigned char reserved; + unsigned short numlines; + unsigned short segnum; +} FIRSTLINEENTRY32; + +typedef struct _SSFILENUM32 +{ + unsigned long first_displayable; // Not used + unsigned long number_displayable; // Not used + unsigned long file_count; // number of source files +} SSFILENUM32; + +/* + *@@ XDEBUGINFO: + * buffers for Read... funcs. + * + *@@added V0.9.4 (2000-06-15) [umoeller] + */ + +typedef struct _XDEBUGINFO +{ + char szNrFile[300]; // receives source file + char szNrLine[300]; // receives line number + //YD 17/07/06 c++ namespace can generate really long + //YD names, use a large buffer! + char szNrPub[16*1024]; // receives function name + + struct new_seg *pseg; + struct o32_obj *pobj; // flat .EXE object table entry + + SYMBASE base; + + SSDIR *pDirTab; + SSDIR32 *pDirTab32; + unsigned char *pEntTab; + unsigned long lfaBase; + SSMOD32 ssmod32; + SSPUBLIC32 sspub32; + + SSMODULE ssmod; + SSPUBLIC sspub; +} XDEBUGINFO, *PXDEBUGINFO; + + +USHORT _THUNK_FUNCTION (Dos16SizeSeg) (); +//APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size); +USHORT DosSizeSeg (USHORT Seg, PULONG16 Size) +{ + return ((USHORT) + (_THUNK_PROLOG (2+4); + _THUNK_SHORT (Seg); + _THUNK_FLAT (Size); + _THUNK_CALL (Dos16SizeSeg))); +} + +#pragma pack() + +/* ****************************************************************** + * + * PART 1: ANALYZE DEBUG CODE + * + ********************************************************************/ + +static int Read16CodeView(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName); +static int Read32PmDebug(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName); + +/* + *@@ WriteAddressInfo: + * formats and writes a line into the trap log + * file. + * + * This gets called for each line from the + * stack dump. At this point, the line in the + * trap log already has: + * + + CS:EIP : 000109FF XMLVIEW :0 + + ^^^ and we write here + * After this call, we have. + * + + CS:EIP : 000109FF XMLVIEW :0 xxx.c 123 ConfirmCreate__Fv + + ^^^ and we write here + * + *@@added V0.9.12 (2001-05-12) [umoeller] + */ + +static VOID WriteDebugInfo(FILE *LogFile, // in: open log file + PXDEBUGINFO pxdi) // in: debug info +{ + fprintf(LogFile, + "%s%s%s", + pxdi->szNrFile, + pxdi->szNrLine, + pxdi->szNrPub); +} + +/* + *@@ dbgPrintDebugInfo: + * this is the main entry point into analyzing debug + * code. + * + * This analyzes a given address and tries to find + * debug code descriptions for this address. If found, + * the information is written to the given log file. + * + * Gets called from dbgPrintStack. + * + * This returns NO_ERROR if the could was successfully + * analyzed or something != 0 if we failed. + * + * New with V0.84. + */ + +APIRET dbgPrintDebugInfo(FILE *LogFile, // out: log file to write to + CHAR *FileName, // in: EXE/DLL module file name + ULONG Object, // in: trapping object (from DosQueryModFromEIP) + ULONG TrapOffset) // in: trapping address (from DosQueryModFromEIP) +{ + APIRET rc = 0; + int ModuleFile = 0; + static struct exe_hdr OldExeHeader; + static struct new_exe NewExeHeader; + + ULONG ulSegment = Object + 1; // segment no. is object no. + 1 + + XDEBUGINFO xdi; + memset(&xdi, 0, sizeof(xdi)); + + // open the module file for reading to analyze the code + ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO); + + if (ModuleFile != -1) + { + // file found: + // read old Exe header + if (read(ModuleFile, (void*)&OldExeHeader, 64) == -1L) + { + fprintf(LogFile, "errno %d reading old exe header\n", errno); + close(ModuleFile); + return 2; + } + // seek to new Exe header + if (lseek(ModuleFile, (long)E_LFANEW(OldExeHeader), SEEK_SET) == -1L) + { + fprintf(LogFile, "errno %d seeking to new exe header\n", errno); + close(ModuleFile); + return 3; + } + if (read(ModuleFile, (void *)&NewExeHeader, 64) == -1L) + { + fprintf(LogFile, "errno %d reading new exe header\n", errno); + close(ModuleFile); + return 4; + } + + // check EXE signature + if (NE_MAGIC(NewExeHeader) == E32MAGIC) + { + /* + * flat 32 executable: + * + */ + + // do analysis for 32-bit code + if (!(rc = Read32PmDebug(LogFile, + &xdi, // output + ModuleFile, + ulSegment, + TrapOffset, + FileName))) + WriteDebugInfo(LogFile, &xdi); + + close(ModuleFile); + + // rc !=0 try with DBG file + if (rc != 0) + { + strcpy(FileName + strlen(FileName) - 3, "DBG"); // Build DBG File name + ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO); + if (ModuleFile != -1) + { + if (!(rc = Read32PmDebug(LogFile, + &xdi, + ModuleFile, + ulSegment, + TrapOffset, + FileName))) + WriteDebugInfo(LogFile, &xdi); + + close(ModuleFile); + } + } + + return rc; + } + else + { + if (NE_MAGIC(NewExeHeader) == NEMAGIC) + { + /* + * 16:16 executable: + * + */ + + if ((xdi.pseg = (struct new_seg *)calloc(NE_CSEG(NewExeHeader), + sizeof(struct new_seg))) + == NULL) + { + fprintf(LogFile, "Out of memory!"); + close(ModuleFile); + return -1; + } + if ( lseek(ModuleFile, + E_LFANEW(OldExeHeader) + NE_SEGTAB(NewExeHeader), + SEEK_SET) == -1L) + { + fprintf(LogFile, "Error %u seeking segment table in %s\n", errno, FileName); + free(xdi.pseg); + close(ModuleFile); + return 9; + } + + if (read(ModuleFile, + (void *)xdi.pseg, + NE_CSEG(NewExeHeader) * sizeof(struct new_seg)) + == -1) + { + fprintf(LogFile, "Error %u reading segment table from %s\n", errno, FileName); + free(xdi.pseg); + close(ModuleFile); + return 10; + } + + if (!(rc = Read16CodeView(LogFile, + &xdi, + ModuleFile, + ulSegment, + TrapOffset, + FileName))) + WriteDebugInfo(LogFile, &xdi); + + free(xdi.pseg); + close(ModuleFile); + + // rc !=0 try with DBG file + if (rc != 0) + { + strcpy(FileName + strlen(FileName) - 3, "DBG"); // Build DBG File name + ModuleFile = sopen(FileName, + O_RDONLY | O_BINARY, SH_DENYNO); + if (ModuleFile != -1) + { + if (!(rc = Read16CodeView(LogFile, + &xdi, + ModuleFile, + ulSegment, + TrapOffset, + FileName))) + WriteDebugInfo(LogFile, &xdi); + + close(ModuleFile); + } + } + return rc; + } + else + { + /* + * Unknown executable: + * + */ + + fprintf(LogFile, "Error, could not find exe signature"); + close(ModuleFile); + return 11; + } + } + } // end if (ModuleFile != -1) + else + { + fprintf(LogFile, "Error %d opening module file %s", errno, FileName); + return 1; + } // endif + + // return 0; we never get here +} + +char fname[256], + ModName[80]; +char ename[256], + dummy[256]; + +#define MAX_USERDEFS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller] +#define MAX_POINTERS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller] + +USHORT userdef_count; +USHORT pointer_count; + +struct one_userdef_rec +{ + USHORT idx; + USHORT type_index; + BYTE name[33]; +} one_userdef[MAX_USERDEFS]; + +struct one_pointer_rec +{ + USHORT idx; + USHORT type_index; + BYTE type_qual; + BYTE name[33]; +} one_pointer[MAX_POINTERS]; + +/* + * Read32PmDebug: + * parses 32-bit debug code. + * Called from dbgPrintDebugInfo for 32-bit modules. + */ + +static int Read32PmDebug(FILE *LogFile, // in: text log file to write to + PXDEBUGINFO pxdi, + int ModuleFile, // in: module file opened with sopen() + int TrapSeg, + int TrapOff, + CHAR *FileName) +{ + static unsigned int CurrSymSeg, NrSymbol, + /* offset, */ NrPublic, + NrFile, NrLine, /* NrEntry */ + numdir, namelen, + numlines /* , line */; + static int ModIndex; + static int bytesread, i, j; + static SSLINEENTRY32 LineEntry; + static SSFILENUM32 FileInfo; + static FIRSTLINEENTRY32 FirstLine; + static BYTE dump_vars = FALSE; + static USHORT idx; + static BOOL read_types; + static LONG lSize; + + ModIndex = 0; + // See if any CODEVIEW info + if (lseek(ModuleFile, -8L, SEEK_END) == -1) + { + fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName); + return (18); + } + + if (read(ModuleFile, + (void *)&G_eodbug, 8) + == -1) + { + fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName); + return (19); + } + if (G_eodbug.dbug != DBUGSIG) + { + // fprintf(LogFile,"\nNo CodeView information stored.\n"); + return (100); + } + + if ( (pxdi->lfaBase = lseek(ModuleFile, + -(LONG)G_eodbug.dfaBase, + SEEK_END)) + == -1L) + { + fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName); + return (20); + } + + if (read(ModuleFile, + (void *)&pxdi->base, 8) + == -1) + { + fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName); + return (21); + } + + if (lseek(ModuleFile, + pxdi->base.lfoDir - 8 + 4, + SEEK_CUR) + == -1) + { + fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName); + return (22); + } + + if (read(ModuleFile, + (void *)&numdir, 4) + == -1) + { + fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName); + return (23); + } + + // Read dir table into buffer + if ( (pxdi->pDirTab32 = (SSDIR32*)calloc(numdir, + sizeof(SSDIR32))) + == NULL) + { + fprintf(LogFile, "Out of memory!"); + return (-1); + } + + if (read(ModuleFile, + (void*)pxdi->pDirTab32, + numdir * sizeof(SSDIR32)) + == -1) + { + fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName); + free(pxdi->pDirTab32); + return (24); + } + + i = 0; + while (i < numdir) + { + if (pxdi->pDirTab32[i].sst != SSTMODULES) + { + i++; + continue; + } + + NrPublic = 0x0; + NrSymbol = 0; + NrLine = 0x0; + NrFile = 0x0; + CurrSymSeg = 0; + // point to subsection + lseek(ModuleFile, + pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase, + SEEK_SET); + read(ModuleFile, + (void*)&pxdi->ssmod32.csBase, + sizeof(SSMOD32)); + read(ModuleFile, + (void*)ModName, + (unsigned)pxdi->ssmod32.csize); + ModIndex = pxdi->pDirTab32[i].modindex; + ModName[pxdi->ssmod32.csize] = '\0'; + i++; + + read_types = FALSE; + + while ( (pxdi->pDirTab32[i].modindex == ModIndex) + && (i < numdir) + ) + { + // point to subsection + lseek(ModuleFile, + pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase, + SEEK_SET); + + switch (pxdi->pDirTab32[i].sst) + { + case SSTPUBLICS: + bytesread = 0; + while (bytesread < pxdi->pDirTab32[i].cb) + { + bytesread += read(ModuleFile, + (void *)&pxdi->sspub32.offset, + sizeof(pxdi->sspub32)); + bytesread += read(ModuleFile, + (void*)ename, + (unsigned)pxdi->sspub32.csize); + ename[pxdi->sspub32.csize] = '\0'; + if ( (pxdi->sspub32.segment == TrapSeg) + && (pxdi->sspub32.offset <= TrapOff) + && (pxdi->sspub32.offset >= NrPublic) + ) + { + NrPublic = pubfunc_ofs = pxdi->sspub32.offset; + read_types = TRUE; + sprintf(pxdi->szNrPub, + "%s %s (%s)\n", + (pxdi->sspub32.type == 1) + ? " Abs" + : " ", + ename, + ModName + ); + // but continue, because there might be a + // symbol that comes closer + } + } + break; + + // Read symbols, so we can dump the variables on the stack + case SSTSYMBOLS: + if (TrapSeg != pxdi->ssmod32.csBase) + break; + + bytesread = 0; + while (bytesread < pxdi->pDirTab32[i].cb) + { + static USHORT usLength; + static USHORT usLengthSym; + static BYTE b1, + b2; + static BYTE bType; + // *ptr; + static ULONG ofs; + // static ULONG last_addr = 0; + //YD 17/07/06 c++ namespace can generate really long + //YD names, use a large buffer! + static BYTE str[16*1024]; + static struct symseg_rec symseg; + static struct symauto_rec symauto; + static struct symproc_rec symproc; + + // Read the length of this subentry + bytesread += read(ModuleFile, &b1, 1); + if (b1 & 0x80) + { + bytesread += read(ModuleFile, &b2, 1); + usLength = ((b1 & 0x7F) << 8) + b2; + } + else + usLength = b1; + + ofs = tell(ModuleFile); + + bytesread += read(ModuleFile, &bType, 1); + + switch (bType) + { + case SYM_CHANGESEG: + read(ModuleFile, &symseg, sizeof(symseg)); + CurrSymSeg = symseg.seg_no; + break; + + case SYM_PROC: + case SYM_CPPPROC: + read(ModuleFile, &symproc, sizeof(symproc)); + if (symproc.name_len & 0x80) + { + read(ModuleFile, &b2, 1); + usLengthSym = ((symproc.name_len & 0x7F) << 8) + b2; + } + else + { + usLengthSym = symproc.name_len; + } + read(ModuleFile, str, usLengthSym); + str[usLengthSym] = 0; + + if ((CurrSymSeg == TrapSeg) && + (symproc.offset <= TrapOff) && + (symproc.offset >= NrSymbol)) + { + + dump_vars = TRUE; + var_ofs = 0; + NrSymbol = symproc.offset; + func_ofs = symproc.offset; + + strcpy(func_name, str); + } + else + { + dump_vars = FALSE; + } + break; + + case SYM_AUTO: + if (!dump_vars) + break; + + read(ModuleFile, &symauto, sizeof(symauto)); + read(ModuleFile, str, symauto.name_len); + if (symauto.name_len==0x80) + printf("symauto.name_len==0x80\n"); + str[symauto.name_len] = 0; + + strcpy(autovar_def[var_ofs].name, str); + autovar_def[var_ofs].stack_offset = symauto.stack_offset; + autovar_def[var_ofs].type_idx = symauto.type_idx; + var_ofs++; + break; + + } + + bytesread += usLength; + + lseek(ModuleFile, ofs + usLength, SEEK_SET); + } + break; + + case SSTTYPES: + // if (ModIndex != TrapSeg) + if (!read_types) + break; + + bytesread = 0; + idx = 0x200; + userdef_count = 0; + pointer_count = 0; + while (bytesread < pxdi->pDirTab32[i].cb) + { + static struct type_rec type; + static struct type_userdefrec udef; + static struct type_pointerrec point; + static ULONG ofs; + static BYTE str[256]; + + // Read the length of this subentry + ofs = tell(ModuleFile); + + read(ModuleFile, &type, sizeof(type)); + bytesread += sizeof(type); + + switch (type.type) + { + case TYPE_USERDEF: + if (userdef_count >= MAX_USERDEFS) + break; + + read(ModuleFile, &udef, sizeof(udef)); + read(ModuleFile, str, udef.name_len); + str[udef.name_len] = 0; + + // Insert userdef in table + one_userdef[userdef_count].idx = idx; + one_userdef[userdef_count].type_index = udef.type_index; + memcpy(one_userdef[userdef_count].name, + str, + _min(udef.name_len + 1, 32)); + one_userdef[userdef_count].name[32] = 0; + userdef_count++; + break; + + case TYPE_POINTER: + if (pointer_count >= MAX_POINTERS) + break; + + read(ModuleFile, &point, sizeof(point)); + read(ModuleFile, str, point.name_len); + str[point.name_len] = 0; + + // Insert userdef in table + one_pointer[pointer_count].idx = idx; + one_pointer[pointer_count].type_index = point.type_index; + memcpy(one_pointer[pointer_count].name, + str, + _min(point.name_len + 1, 32)); + one_pointer[pointer_count].name[32] = 0; + one_pointer[pointer_count].type_qual = type.type_qual; + pointer_count++; + break; + } + + ++idx; + + bytesread += type.length; + + lseek(ModuleFile, ofs + type.length + 2, SEEK_SET); + } + break; + + case SSTSRCLINES32: + if (TrapSeg != pxdi->ssmod32.csBase) + break; + + // read first line + do + { + read(ModuleFile, (void *)&FirstLine, sizeof(FirstLine)); + + if (FirstLine.LineNum != 0) + { + fprintf(LogFile, "Missing Line table information\n"); + break; + } // endif + numlines = FirstLine.numlines; + // Other type of data skip 4 more bytes + if (FirstLine.entry_type < 4) + { + read(ModuleFile, (void *)&lSize, 4); + if (FirstLine.entry_type == 3) + lseek(ModuleFile, lSize, SEEK_CUR); + } + } + while (FirstLine.entry_type == 3); + + for (j = 0; j < numlines; j++) + { + switch (FirstLine.entry_type) + { + case 0: + read(ModuleFile, (void *)&LineEntry, sizeof(LineEntry)); + // Changed by Kim Rasmussen 26/06 1996 to ignore linenumber 0 + // if (LineEntry.Offset+ssmod32.csOff<=TrapOff && LineEntry.Offset+ssmod32.csOff>=NrLine) { + if ( (LineEntry.LineNum) + && (LineEntry.Offset + pxdi->ssmod32.csOff + <= TrapOff) + && (LineEntry.Offset + pxdi->ssmod32.csOff >= NrLine) + ) + { + NrLine = LineEntry.Offset; + NrFile = LineEntry.FileNum; + /*pOffset =sprintf(szNrLine,"%04X:%08X line #%hu ", + * ssmod32.csBase,LineEntry.Offset, + * LineEntry.LineNum); */ + sprintf(pxdi->szNrLine, "% 6hu", LineEntry.LineNum); + } + break; + + case 1: + lseek(ModuleFile, sizeof(struct linlist_rec), SEEK_CUR); + break; + + case 2: + lseek(ModuleFile, sizeof(struct linsourcelist_rec), SEEK_CUR); + break; + + case 3: + lseek(ModuleFile, sizeof(struct filenam_rec), SEEK_CUR); + break; + + case 4: + lseek(ModuleFile, sizeof(struct pathtab_rec), SEEK_CUR); + break; + + } + } + + if (NrFile != 0) + { + // file found: + read(ModuleFile, (void*)&FileInfo, sizeof(FileInfo)); + namelen = 0; + for (j = 1; j <= FileInfo.file_count; j++) + { + namelen = 0; + read(ModuleFile, (void *)&namelen, 1); + read(ModuleFile, (void *)ename, namelen); + if (j == NrFile) + break; + } + ename[namelen] = '\0'; + // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName); + sprintf(pxdi->szNrFile, "%11.11s ", ename); + } + else + { + // strcat(szNrLine,"\n"); avoid new line for empty name fill + strcpy(pxdi->szNrFile, "file? "); + } // endif + break; + } // end switch + + i++; + } // end while modindex + } // End While i < numdir + free(pxdi->pDirTab32); + return (0); +} + +/* + * Read16CodeView: + * parses 16-bit debug code. + * Called from dbgPrintDebugInfo for 16-bit modules. + */ + +static int Read16CodeView(FILE *LogFile, // in: text log file to write to + PXDEBUGINFO pxdi, + int fh, + int TrapSeg, + int TrapOff, + CHAR *FileName) +{ + static unsigned short int offset, + NrPublic, NrLine, + numdir, + namelen, numlines, + line; + static int ModIndex; + static int bytesread, i, j; + + ModIndex = 0; + // See if any CODEVIEW info + if (lseek(fh, -8L, SEEK_END) == -1) + { + fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName); + return (18); + } + + if (read(fh, (void *)&G_eodbug, 8) == -1) + { + fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName); + return (19); + } + if (G_eodbug.dbug != DBUGSIG) + { + // fprintf(LogFile,"\nNo CodeView information stored.\n"); + return (100); + } + + if ((pxdi->lfaBase = lseek(fh, -(LONG)G_eodbug.dfaBase, SEEK_END)) == -1L) + { + fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName); + return (20); + } + + if (read(fh, (void *)&pxdi->base, 8) == -1) + { + fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName); + return (21); + } + + if (lseek(fh, pxdi->base.lfoDir - 8, SEEK_CUR) == -1) + { + fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName); + return (22); + } + + if (read(fh, (void *)&numdir, 2) == -1) + { + fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName); + return (23); + } + + // Read dir table into buffer + if ((pxdi->pDirTab = (SSDIR*)calloc(numdir, sizeof(SSDIR))) == NULL) + { + fprintf(LogFile, "Out of memory!"); + return (-1); + } + + if (read(fh, (void*)pxdi->pDirTab, numdir * sizeof(SSDIR)) == -1) + { + fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName); + free(pxdi->pDirTab); + return (24); + } + + i = 0; + while (i < numdir) + { + if (pxdi->pDirTab[i].sst != SSTMODULES) + { + i++; + continue; + } + NrPublic = 0x0; + NrLine = 0x0; + // point to subsection + lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET); + read(fh, (void *)&pxdi->ssmod.csBase, sizeof(SSMODULE)); + read(fh, (void *)ModName, (unsigned)pxdi->ssmod.csize); + ModIndex = pxdi->pDirTab[i].modindex; + ModName[pxdi->ssmod.csize] = '\0'; + i++; + while (pxdi->pDirTab[i].modindex == ModIndex && i < numdir) + { + // point to subsection + lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET); + switch (pxdi->pDirTab[i].sst) + { + case SSTPUBLICS: + bytesread = 0; + while (bytesread < pxdi->pDirTab[i].cb) + { + bytesread += read(fh, (void *)&pxdi->sspub.offset, sizeof(pxdi->sspub)); + bytesread += read(fh, (void *)ename, (unsigned)pxdi->sspub.csize); + ename[pxdi->sspub.csize] = '\0'; + if ((pxdi->sspub.segment == TrapSeg) && + (pxdi->sspub.offset <= TrapOff) && + (pxdi->sspub.offset >= NrPublic)) + { + NrPublic = pxdi->sspub.offset; + sprintf(pxdi->szNrPub, "%s %s (%s) %04hX:%04hX\n", + (pxdi->sspub.type == 1) ? " Abs" : " ", ename, + ModName, // () + pxdi->sspub.segment, + pxdi->sspub.offset + ); + } + } + break; + + case SSTSRCLINES2: + case SSTSRCLINES: + if (TrapSeg != pxdi->ssmod.csBase) + break; + namelen = 0; + read(fh, (void *)&namelen, 1); + read(fh, (void *)ename, namelen); + ename[namelen] = '\0'; + // skip 2 zero bytes + if (pxdi->pDirTab[i].sst == SSTSRCLINES2) + read(fh, (void *)&numlines, 2); + read(fh, (void *)&numlines, 2); + for (j = 0; j < numlines; j++) + { + read(fh, (void *)&line, 2); + read(fh, (void *)&offset, 2); + if (offset <= TrapOff && offset >= NrLine) + { + NrLine = offset; + sprintf(pxdi->szNrFile, "% 12.12s ", ename); + sprintf(pxdi->szNrLine, "% 6hu", line); + /*sprintf(szNrLine,"%04hX:%04hX line #%hu (%s) (%s)\n", + * ssmod.csBase,offset,line,ModName,ename); */ + } + } + break; + } // end switch + i++; + } // end while modindex + } // End While i < numdir + free(pxdi->pDirTab); + return (0); +} + +/* ****************************************************************** + * + * PART 2: ANALYZE VARIABLES + * + ********************************************************************/ + +/* + * var_value: + * writes a description of a variable type to + * the specified buffer, depending on "type". + * + *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer + */ + +static VOID var_value(void *varptr, // in: address of the variable on the stack + char *pszBuf, // out: information + BYTE type) // in: type; if >= 32, we'll call DosQueryMem +{ + ULONG Size = 1, + Attr = 0; + + if (DosQueryMem(varptr, &Size, &Attr) != NO_ERROR) + { + sprintf(pszBuf, "type %d, DosQueryMem failed", type); + return; + } + + if ((Attr & PAG_READ) == 0) + { + sprintf(pszBuf, "type %d, read-access to value denied", type); + return; + } + + if (type == 0) + sprintf(pszBuf, "%hd", *(signed char*)varptr); + else if (type == 1) + sprintf(pszBuf, "%hd", *(signed short*)varptr); + else if (type == 2) + sprintf(pszBuf, "%ld", *(signed long*)varptr); + else if (type == 4) + sprintf(pszBuf, "%hu", *(BYTE*) varptr); + else if (type == 5) + sprintf(pszBuf, "%hu", *(USHORT*)varptr); + else if (type == 6) + sprintf(pszBuf, "0x%lX (%lu)", *((ULONG*)varptr), *((ULONG*)varptr)); + else if (type == 8) + sprintf(pszBuf, "%f", *(float*)varptr); + else if (type == 9) + sprintf(pszBuf, "%f", *(double*)varptr); + else if (type == 10) + sprintf(pszBuf, "%f", (double)(*(long double*)varptr)); + else if (type == 16) + sprintf(pszBuf, "%s", *(char*)varptr ? "TRUE" : "FALSE"); + else if (type == 17) + sprintf(pszBuf, "%s", *(short*)varptr ? "TRUE" : "FALSE"); + else if (type == 18) + sprintf(pszBuf, "%s", *(long*)varptr ? "TRUE" : "FALSE"); + else if (type == 20) + sprintf(pszBuf, "%c", *(char*)varptr); + else if (type == 21) + sprintf(pszBuf, "%hd", (*(short*)varptr)); + else if (type == 22) + sprintf(pszBuf, "%ld", *(long*)varptr); + else if (type == 23) + sprintf(pszBuf, "void"); + else if (type >= 32) + { + sprintf(pszBuf, "0x%p", (void*)(*(ULONG*)varptr)); + if (Attr & PAG_FREE) + { + strcat(pszBuf, " unallocated memory"); + } + else + { + if ((Attr & PAG_COMMIT) == 0x0U) + { + strcat(pszBuf, " uncommitted"); + } // endif + if ((Attr & PAG_WRITE) == 0x0U) + { + strcat(pszBuf, " unwritable"); + } // endif + if ((Attr & PAG_READ) == 0x0U) + { + strcat(pszBuf, " unreadable"); + } // endif + } // endif + } // endif + else + sprintf(pszBuf, "Unknown type %d", type); +} + +/* + * search_userdefs: + * searches the table of userdef's- + * Return TRUE if found. + */ + +static BOOL search_userdefs(FILE *LogFile, // in: text log file to write to + ULONG stackofs, + USHORT var_no) +{ + USHORT pos; + + for (pos = 0; + pos < userdef_count; + pos++) + { + if (one_userdef[pos].idx == autovar_def[var_no].type_idx) + { + if ( (one_userdef[pos].type_index >= 0x80) + // && (one_userdef[pos].type_index <= 0xDA) + ) + { + static char sszVar3[500] = "complex"; + if (one_userdef[pos].type_index <= 0xDA) + var_value((void*)(stackofs + autovar_def[var_no].stack_offset), + sszVar3, + one_userdef[pos].type_index - 0x80); + + fprintf(LogFile, + " %- 6ld %- 20.20s %- 33.33s %s (user)\n", + autovar_def[var_no].stack_offset, // stack offset + autovar_def[var_no].name, // identifier + one_userdef[pos].name, // type name + sszVar3 // composed by var_value + ); + return TRUE; + } + else + return FALSE; + } + } + + return FALSE; +} + +/* + * search_pointers: + * + */ + +static BOOL search_pointers(FILE *LogFile, // in: text log file to write to + ULONG stackofs, + USHORT var_no) +{ + USHORT pos, upos; + static BYTE str[35]; + static char sszVar[500]; + + // BYTE type_index; + + for (pos = 0; + ( (pos < pointer_count) + && (one_pointer[pos].idx != autovar_def[var_no].type_idx) + ); + pos++); + + if (pos < pointer_count) + { + if ( (one_pointer[pos].type_index >= 0x80) + && (one_pointer[pos].type_index <= 0xDA) + ) + { + strcpy(str, type_name[one_pointer[pos].type_index - 0x80]); + strcat(str, " *"); + var_value((void*)(stackofs + autovar_def[var_no].stack_offset), + sszVar, + 32); + fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n", + autovar_def[var_no].stack_offset, + autovar_def[var_no].name, + str, + sszVar); + return TRUE; + } + else + { + // If the result isn't a simple type, look for it in the other lists + for (upos = 0; + ( (upos < userdef_count) + && (one_userdef[upos].idx != one_pointer[pos].type_index) + ); + upos++) + ; + + if (upos < userdef_count) + { + strcpy(str, one_userdef[upos].name); + strcat(str, " *"); + var_value((void *)(stackofs + autovar_def[var_no].stack_offset), + sszVar, + 32); + fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n", + autovar_def[var_no].stack_offset, + autovar_def[var_no].name, + str, + sszVar); + return TRUE; + } + else + { + // if it isn't a userdef, for now give up and just print + // as much as we know + sprintf(str, "Pointer to type 0x%X", one_pointer[pos].type_index); + + var_value((void *)(stackofs + autovar_def[var_no].stack_offset), + sszVar, + 32); + fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n", + autovar_def[var_no].stack_offset, + autovar_def[var_no].name, + str, + sszVar); + + return TRUE; + } + } + } + + return FALSE; +} + +/* + *@@ dbgPrintVariables: + * Dumps variables for the specified stack offset + * to the specified log file. + * + * New with V0.84. + */ + +void dbgPrintVariables(FILE *LogFile, // in: text log file to write to + ULONG stackofs) +{ + USHORT n; // , pos; + BOOL AutoVarsFound = FALSE; + + if (/* 1 || */ func_ofs == pubfunc_ofs) + { + for (n = 0; + n < var_ofs; + n++) + { + if (AutoVarsFound == FALSE) + { + AutoVarsFound = TRUE; + fprintf(LogFile, " List of auto variables at EBP %p in %s:\n", + (PVOID)stackofs, + func_name); + fprintf(LogFile, " Offset Name Type Value \n"); + fprintf(LogFile, " ������ �������������������� ��������������������������������� �����������������\n"); + } + + // If it's one of the simple types + if ( (autovar_def[n].type_idx >= 0x80) + && (autovar_def[n].type_idx <= 0xDA) + ) + { + static char sszVar2[500]; + + var_value((void *)(stackofs + autovar_def[n].stack_offset), + sszVar2, + autovar_def[n].type_idx - 0x80); + + fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (simple)\n", + autovar_def[n].stack_offset, + autovar_def[n].name, + type_name[autovar_def[n].type_idx - 0x80], + sszVar2); + } + else + { // Complex type, check if we know what it is + if (!search_userdefs(LogFile, stackofs, n)) + { + if (!search_pointers(LogFile, stackofs, n)) + { + fprintf(LogFile, " %- 6ld %-20.20s 0x%X (unknown)\n", + autovar_def[n].stack_offset, + autovar_def[n].name, + autovar_def[n].type_idx); + } + } + } + } + /* if (AutoVarsFound == FALSE) + { + fprintf(LogFile, " No auto variables found in %s.\n", func_name); + } */ + fprintf(LogFile, "\n"); + } +} + +/* ****************************************************************** + * + * PART 3: ANALYZE SYMBOL (.SYM) FILE + * + ********************************************************************/ + +/* + *@@ dbgPrintSYMInfo: + * this gets called by dbgPrintStack if dbgPrintDebugInfo + * failed (because no debug code was found) to check if + * maybe a SYM file with the same filename exists and try + * to get the info from there. + * + * This gets called for every line of the stack + * walk, but only if getting the information from + * the debug code failed, e.g. because no debug code + * was available for an address. + * + * The file pointer is in the "Source file" column + * every time this gets called. + * + * New with V0.84. + * + * Returns 0 if reading the SYM file was successful. + * + *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID + */ + +int dbgPrintSYMInfo(FILE *LogFile, // in: text log file to write to + CHAR *SymFileName, // in: SYM file name (can be fully q'fied) + ULONG Object, + ULONG TrapOffset) +{ + static FILE *SymFile; + static MAPDEF MapDef; + static SEGDEF SegDef; + static SYMDEF32 SymDef32; + static SYMDEF16 SymDef16; + static char Buffer[256]; + static int SegNum, SymNum, LastVal; + static unsigned long int SegOffset, + SymOffset, SymPtrOffset; + + // open .SYM file +#ifdef DEBUG_SYMDUMP + fprintf(LogFile,"Dump of '%s' for object %d\n",SymFileName,Object); +#endif + SymFile = fopen(SymFileName, "rb"); + if (SymFile == 0) + return (2); + + // read in first map definition + fread(&MapDef, sizeof(MAPDEF), 1, SymFile); +#ifdef DEBUG_SYMDUMP + Buffer[0] = MapDef.achModName[0]; + fread(&Buffer[1], 1, MapDef.cbModName-1, SymFile); + Buffer[MapDef.cbModName] = 0x00; + fprintf(LogFile,"Module name '%s'\n",Buffer); +#endif + + SegOffset = SEGDEFOFFSET(MapDef); +#ifdef DEBUG_SYMDUMP + fprintf(LogFile,"SegOffset %0x\n",SegOffset); +#endif + + // go thru all segments + for (SegNum = 0; + SegNum < MapDef.cSegs; + SegNum++) + { +#ifdef DEBUG_SYMDUMP + fprintf(LogFile,"Scanning segment #%d Offset %08X\n",SegNum,SegOffset); +#endif + if (fseek(SymFile, SegOffset, SEEK_SET)) + // seek error + return (3); + + // read in segment definition + fread(&SegDef, sizeof(SEGDEF), 1, SymFile); +#ifdef DEBUG_SYMDUMP + Buffer[0] = 0x00; + if (SegDef.cbSegName>0) { + Buffer[0] = SegDef.achSegName[0]; + fread(&Buffer[1], 1, SegDef.cbSegName-1, SymFile); + Buffer[SegDef.cbSegName] = 0x00; + } + fprintf(LogFile,"Segment name '%s', number %d, flags %02x\n",Buffer,SegNum,SegDef.bFlags); +#endif + + if (SegNum == Object) + { + // stack object found: + Buffer[0] = 0x00; + LastVal = 0; + + // go thru all symbols in this object +#ifdef DEBUG_SYMDUMP + fprintf(LogFile,"Scanning #%d symbols\n",SegDef.cSymbols); +#endif + for (SymNum = 0; SymNum < SegDef.cSymbols; SymNum++) + { + SymPtrOffset=SYMDEFOFFSET(SegOffset,SegDef,SymNum); + fseek(SymFile,SymPtrOffset,SEEK_SET); + fread(&SymOffset,sizeof(unsigned short int),1,SymFile); + fseek(SymFile,SymOffset+SegOffset,SEEK_SET); + if (SegDef.bFlags & 0x01) + { + // 32-bit symbol: + fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile); + if (SymDef32.wSymVal > TrapOffset) + { + // symbol found + fprintf(LogFile, + "between %s + 0x%lX ", + Buffer, + TrapOffset - LastVal); + /* fprintf(LogFile, "(ppLineDef: 0x%lX) ", + LINEDEFOFFSET(SegDef) + ); */ + fprintf(LogFile, "\n"); + } + + LastVal = SymDef32.wSymVal; + Buffer[0] = SymDef32.achSymName[0]; + fread(&Buffer[1], 1, SymDef32.cbSymName-1, SymFile); + Buffer[SymDef32.cbSymName] = 0x00; +#ifdef DEBUG_SYMDUMP + fprintf(LogFile,"32 Bit Symbol Address %08p <%s> \n",SymDef32.wSymVal,Buffer); +#endif + + if (SymDef32.wSymVal > TrapOffset) + { + // symbol found, as above + fprintf(LogFile, + " " + "and %s - 0x%lX ", + Buffer, + LastVal - TrapOffset); + fprintf(LogFile, "\n"); + break; + } + } + else + { + // 16-bit symbol: + fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile); + if (SymDef16.wSymVal > TrapOffset) + { + fprintf(LogFile, + "between %s + %lX\n", + Buffer, + TrapOffset - LastVal); + } + LastVal = SymDef16.wSymVal; + Buffer[0] = SymDef16.achSymName[0]; + fread(&Buffer[1], 1, SymDef16.cbSymName-1, SymFile); + Buffer[SymDef16.cbSymName] = 0x00; + if (SymDef16.wSymVal > TrapOffset) + { + fprintf(LogFile, + " " + "and %s - %lX\n", + Buffer, + LastVal - TrapOffset); + break; + } +#ifdef DEBUG_SYMDUMP + fprintf(LogFile,"16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal); +#endif + } // endif + } + break; + } // endif + SegOffset = NEXTSEGDEFOFFSET(SegDef); + } // endwhile + fclose(SymFile); + return (0); // no error +} + +/* ****************************************************************** + * + * PART 4: dbgPrintStack + * + ********************************************************************/ + +/* + *@@ dbgPrintStackFrame: + * parses and dumps one stack frame. + * Called from excPrintStackFrame. + * + * This calls dbgPrintDebugInfo and, if + * that fails, dbgPrintSYMInfo. + * + *@@added V0.9.2 (2000-03-10) [umoeller] + *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files + *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed + */ + +BOOL dbgPrintStackFrame(FILE *LogFile, + PSZ pszModuleName, // in: module name (fully q'fied) + ULONG ulObject, + ULONG ulOffset) +{ + APIRET arc = 0; + // "Source file"... columns + +//YD do not use debug info +#define ENABLE_DEBUG_INFO +#ifdef ENABLE_DEBUG_INFO + // first attempt to analyze the debug code + arc = dbgPrintDebugInfo(LogFile, + pszModuleName, + ulObject, + ulOffset); +#else + arc = 1; +#endif + + // if no debug code is available, analyze + // the SYM file instead + if (arc != NO_ERROR) + { + CHAR szSymName[CCHMAXPATH]; + strcpy(szSymName, pszModuleName); + strcpy(szSymName + strlen(szSymName) - 3, "SYM"); + arc = dbgPrintSYMInfo(LogFile, + szSymName, + ulObject, + ulOffset); + if (arc != 0) + { + // SYM file not found in current directory: + // check the SYM files in the \OS2 directory, + // depending on the OS/2 version level: + CHAR szSymFile2[CCHMAXPATH]; + PSZ pszFilename = strrchr(szSymName, '\\'); + if (pszFilename) + { + PSZ pszVersionDir = "WARP4"; + ULONG aulBuf[3]; + + DosQuerySysInfo(QSV_VERSION_MAJOR, // 11 + QSV_VERSION_MINOR, // 12 + &aulBuf, sizeof(aulBuf)); + // Warp 3 is reported as 20.30 + // Warp 4 is reported as 20.40 + // Aurora is reported as 20.45 + + if (aulBuf[0] == 20) + { + if (aulBuf[1] == 30) + // Warp 3: + pszVersionDir = "WARP3"; + else if (aulBuf[1] >= 40) + // Warp 4 or higher: + // (NOTE: Warp 4 FP 13 now returns 45 also, + // but the SYM files are still in the WARP4 directory...) + // V0.9.3 (2000-04-26) [umoeller] + pszVersionDir = "WARP4"; + } + + pszFilename++; + sprintf(szSymFile2, + "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s", + doshQueryBootDrive(), + pszVersionDir, + pszFilename); + arc = dbgPrintSYMInfo(LogFile, + szSymFile2, + ulObject, + ulOffset); + + // V0.9.3 (2000-04-26) [umoeller] + if ( (arc != 0) // still not found + && (aulBuf[1] == 45) // and running Aurora or Warp 4 FP13? + ) + { + // Warp Server for e-Business (aka Warp 4.5): + // we use the SYM files for the UNI kernel, + // I have found no way to find out whether + // we're running on an SMP kernel + sprintf(szSymFile2, + "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s", + doshQueryBootDrive(), + "WARP45_U", + pszFilename); + arc = dbgPrintSYMInfo(LogFile, + szSymFile2, + ulObject, + ulOffset); + } + } + } + + if (arc == 2) // file not found + fprintf(LogFile, + "Cannot find symbol file %s\n", + szSymName); + else if (arc != 0) + fprintf(LogFile, + "Error %lu reading symbol file %s\n", + arc, + szSymName); + } + + return (arc == NO_ERROR); +} + +/* + *@@ dbgPrintStack: + * this takes stack data from the TIB and + * context record data structures and tries + * to analyse what the different stack frames + * point to. + * + * For each stack frame, this calls dbgPrintDebugInfo, + * and, if that fails, dbgPrintSYMInfo. + * + * New with V0.84. + * + *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also + */ + +VOID dbgPrintStack(FILE *LogFile, // in: text log file to write to + PUSHORT StackBottom, + PUSHORT StackTop, + PUSHORT Ebp, + PUSHORT ExceptionAddress) +{ + PUSHORT RetAddr = 0; + PUSHORT LastEbp = 0; + APIRET rc = 0; + ULONG Size = 0, + Attr = 0; + USHORT Cs = 0, + Ip = 0, + // Bp, + Sp = 0; + static char Name[CCHMAXPATH]; + HMODULE hMod = 0; + ULONG ObjNum = 0; + ULONG Offset = 0; + BOOL fExceptionAddress = TRUE; // Use Exception Addr 1st time thru + + // Note: we can't handle stacks bigger than 64K for now... + Sp = (USHORT) (((ULONG) StackBottom) >> 16); + // Bp = ; + + if (!f32bit) + Ebp = (PUSHORT) MAKEULONG(((USHORT)(ULONG)Ebp), Sp); + + fprintf(LogFile, "\n\nCall stack:\n"); + fprintf(LogFile, " Source Line Nearest\n"); + fprintf(LogFile, " EBP Address Module Obj# File Numbr Public Symbol\n"); + fprintf(LogFile, " �������� ��������- �������� ���� ������������ ����� ������������-\n"); + + do + { + Size = 10; + rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr); + if (rc != NO_ERROR) + { + fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc); + break; + } + if (!(Attr & PAG_COMMIT)) + { + fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp); + break; + } + if (Size < 10) + { + fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp); + break; + } + + if (fExceptionAddress) + RetAddr = ExceptionAddress; + else + RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2))); + + if (RetAddr == (PUSHORT) 0x00000053) + { + // For some reason there's a "return address" of 0x53 following + // EBP on the stack and we have to adjust EBP by 44 bytes to get + // at the real return address. This has something to do with + // thunking from 32bits to 16bits... + // Serious kludge, and it's probably dependent on versions of C(++) + // runtime or OS, but it works for now! + Ebp += 22; + RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2))); + } + + // Get the (possibly) 16bit CS and IP + if (fExceptionAddress) + { + Cs = (USHORT) (((ULONG) ExceptionAddress) >> 16); + Ip = (USHORT) (ULONG) ExceptionAddress; + } + else + { + Cs = *(Ebp + 2); + Ip = *(Ebp + 1); + } + + // if the return address points to the stack then it's really just + // a pointer to the return address (UGH!). + if ( (USHORT) (((ULONG) RetAddr) >> 16) == Sp + ) + RetAddr = (PUSHORT) (*((PULONG) RetAddr)); + + if (Ip == 0 && *Ebp == 0) + { + // End of the stack so these are both shifted by 2 bytes: + Cs = *(Ebp + 3); + Ip = *(Ebp + 2); + } + + // 16bit programs have on the stack: + // BP:IP:CS + // where CS may be thunked + // + // in dump swapped + // BP IP CS BP CS IP + // 4677 53B5 F7D0 7746 D0F7 B553 + // + // 32bit programs have: + // EBP:EIP + // and you'd have something like this (with SP added) (not + // accurate values) + // + // in dump swapped + // EBP EIP EBP EIP + // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553 + // + // So the basic difference is that 32bit programs have a 32bit + // EBP and we can attempt to determine whether we have a 32bit + // EBP by checking to see if its 'selector' is the same as SP. + // Note that this technique limits us to checking stacks < 64K. + // + // Soooo, if IP (which maps into the same USHORT as the swapped + // stack page in EBP) doesn't point to the stack (i.e. it could + // be a 16bit IP) then see if CS is valid (as is or thunked). + // + // Note that there's the possibility of a 16bit return address + // that has an offset that's the same as SP so we'll think it's + // a 32bit return address and won't be able to successfully resolve + // its details. + if (Ip != Sp) + { + if (DosSizeSeg(Cs, &Size) == NO_ERROR) + { + RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs); + f32bit = FALSE; + } + else if (DosSizeSeg((Cs << 3) + 7, &Size) == NO_ERROR) + { + Cs = (Cs << 3) + 7; + RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs); + f32bit = FALSE; + } + else + f32bit = TRUE; + } + else + f32bit = TRUE; + + + // "EBP" column + if (fExceptionAddress) + fprintf(LogFile, " Trap -> "); + else + fprintf(LogFile, " %8.8lX ", (ULONG)Ebp); + + // "Address" column + if (f32bit) + fprintf(LogFile, ":%8.8lX ", (ULONG)RetAddr); + else + fprintf(LogFile, "%04.04X:%04.04X ", Cs, Ip); + + // Version check omitted; the following requires + // OS/2 2.10 or later (*UM) + // if (Version[0] >= 20 && Version[1] >= 10) + { + // Make a 'tick' sound to let the user know we're still alive + DosBeep(2000, 10); + + Size = 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0 + + // "Module"/"Object" columns + rc = DosQueryMem((PVOID) RetAddr, &Size, &Attr); + if (rc != NO_ERROR || !(Attr & PAG_COMMIT)) + { + fprintf(LogFile, "Invalid RetAddr: %8.8lX\n", (ULONG)RetAddr); + break; // avoid infinite loops + } + else + { + rc = DosQueryModFromEIP(&hMod, + &ObjNum, + sizeof(Name), Name, + &Offset, + (PVOID)RetAddr); + if ( (rc == NO_ERROR) + // && (ObjNum != -1) + ) + { + // static char szJunk[_MAX_FNAME]; + static char szName[_MAX_FNAME]; + + DosQueryModuleName(hMod, sizeof(Name), Name); + // _splitpath(Name, szJunk, szJunk, szName, szJunk); + + // print module and object + fprintf(LogFile, "%-8s %04lX ", szName, ObjNum + 1); + + if (strlen(Name) > 3) + { + dbgPrintStackFrame(LogFile, + Name, + ObjNum, + Offset); + } + } + else + fprintf(LogFile, + "DosQueryModFromEIP failed, returned %lu\n", + rc); + } + } + + if ( ((*Ebp) == 0) + && ((*Ebp + 1) == 0) + ) + { + fprintf(LogFile, "End of call stack\n"); + break; + } + + if (!fExceptionAddress) + { + LastEbp = Ebp; +#if 0 + Ebp = (PUSHORT) MAKEULONG(Bp, Sp); +#else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks + if (f32bit) + Ebp = (PUSHORT) *(PULONG) LastEbp; + else + Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp); +#endif + if (f32bit) + { + dbgPrintVariables(LogFile, (ULONG) Ebp); + } // endif + + if (Ebp < LastEbp) + { + fprintf(LogFile, "... lost stack chain - new EBP below previous\n"); + break; + } + } + else + fExceptionAddress = FALSE; + + Size = 4; + rc = DosQueryMem((PVOID) Ebp, &Size, &Attr); + if ((rc != NO_ERROR) || (Size < 4)) + { + fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG)Ebp); + break; + } + } while (TRUE); + + fprintf(LogFile, "\n"); +} + +/* + *@@ doshQueryBootDrive: + * returns the letter of the boot drive as a + * single (capital) character, which is useful for + * constructing file names using sprintf and such. + * + *@@changed V0.9.16 (2002-01-13) [umoeller]: optimized + */ + +CHAR doshQueryBootDrive(VOID) +{ + // this can never change, so query this only once + // V0.9.16 (2002-01-13) [umoeller] + static CHAR cBootDrive = '\0'; + + if (!cBootDrive) + { + ULONG ulBootDrive; + DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, + sizeof(ulBootDrive)); + cBootDrive = (CHAR)ulBootDrive + 'A' - 1; + } + + return (cBootDrive); +} diff --git a/sal/osl/os2/diagnose.c b/sal/osl/os2/diagnose.c new file mode 100644 index 000000000000..4921e20fd5af --- /dev/null +++ b/sal/osl/os2/diagnose.c @@ -0,0 +1,178 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#include <osl/diagnose.h> +#include <osl/thread.h> + +BYTE oslTraceEnv[] = "OSL_TRACE_TO_FILE"; + +typedef pfunc_osl_printDebugMessage oslDebugMessageFunc; +static oslDebugMessageFunc volatile g_pDebugMessageFunc = 0; + +typedef pfunc_osl_printDetailedDebugMessage oslDetailedDebugMessageFunc; +static oslDetailedDebugMessageFunc volatile g_pDetailedDebugMessageFunc = 0; + +/*----------------------------------------------------------------------------*/ + +void SAL_CALL osl_breakDebug() +{ + __asm__("int $3\n"); +} + +/************************************************************************/ +/* osl_trace */ +/************************************************************************/ +/* comment this define to stop output thread identifier*/ +#define OSL_TRACE_THREAD 1 +void SAL_CALL osl_trace ( + const sal_Char* lpszFormat, ...) +{ + va_list args; + +#if defined(OSL_PROFILING) + fprintf(stderr, "Time: %06lu : ", osl_getGlobalTimer() ); +#else +#if defined(OSL_TRACE_THREAD) + fprintf(stderr,"Thread: %6d :",osl_getThreadIdentifier(NULL)); +#else + fprintf(stderr, "Trace Message: "); +#endif +#endif + + va_start(args, lpszFormat); + vfprintf(stderr, lpszFormat, args); + va_end(args); + + fprintf(stderr,"\n"); + fflush(stderr); +} + +/*----------------------------------------------------------------------------*/ + +void SAL_CALL osl_trace__yd_os2(const sal_Char* lpszFormat, ...) +{ + + int nBuf; + sal_Char szBuffer[512]; + sal_Char szPID[ 12 ]; + va_list args; + FILE* pFile; + PID pid; + PSZ pszOslTraceFile; + + /* if environment variable not set, do nothing */ + if(DosScanEnv(oslTraceEnv, (PSZ*)&pszOslTraceFile)) + { + return; + } + + va_start(args, lpszFormat); + + nBuf = vsprintf(szBuffer, lpszFormat, args); + OSL_ASSERT(nBuf < sizeof(szBuffer)); + + va_end(args); + + /* get process ID */ + { + PTIB pptib = NULL; + PPIB pppib = NULL; + + DosGetInfoBlocks( &pptib, &pppib ); + pid = pppib->pib_ulpid; + } + + pFile = fopen( (const char*)pszOslTraceFile, "a+" ); + fputs(_itoa( pid, szPID, 10 ), pFile ); + fputs( ": ", pFile ); + fputs(szBuffer, pFile); + fclose( pFile ); + +} + +/*----------------------------------------------------------------------------*/ + +sal_Bool SAL_CALL osl_assertFailedLine( const sal_Char* pszFileName, sal_Int32 nLine, const sal_Char* pszMessage) +{ + sal_Char szMessage[512]; + + /* get app name or NULL if unknown (don't call assert) */ + sal_Char* lpszAppName = "OSL"; + + /* format message into buffer */ + sprintf(szMessage, "Assertion Failed: %s: File %s, Line %d:\n", + lpszAppName, pszFileName, nLine); + if(pszMessage != 0) + strcat( szMessage, pszMessage ); + + szMessage[sizeof(szMessage)-1] = '\0'; + + fputs(szMessage, stderr); + + return sal_True; /* abort */ +} + +/*----------------------------------------------------------------------------*/ + +sal_Int32 SAL_CALL osl_reportError(sal_uInt32 nType, const sal_Char* pszMessage) +{ + fputs(pszMessage, stderr); + + return 0; +} + +/*----------------------------------------------------------------------------*/ + + +/************************************************************************/ +/* osl_setDebugMessageFunc */ +/************************************************************************/ +oslDebugMessageFunc SAL_CALL osl_setDebugMessageFunc ( + oslDebugMessageFunc pNewFunc) +{ + oslDebugMessageFunc pOldFunc = g_pDebugMessageFunc; + g_pDebugMessageFunc = pNewFunc; + return pOldFunc; +} + +/************************************************************************/ +/* osl_setDetailedDebugMessageFunc */ +/************************************************************************/ +pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc ( + pfunc_osl_printDetailedDebugMessage pNewFunc) +{ + oslDetailedDebugMessageFunc pOldFunc = g_pDetailedDebugMessageFunc; + g_pDetailedDebugMessageFunc = pNewFunc; + return pOldFunc; +} diff --git a/sal/osl/os2/dllentry.c b/sal/osl/os2/dllentry.c new file mode 100644 index 000000000000..494119599f8b --- /dev/null +++ b/sal/osl/os2/dllentry.c @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" +#include "sockimpl.h" +#include "secimpl.h" +//#include "daemimpl.h" + +#include <osl/diagnose.h> + +#ifndef GCC +sal_uInt32 _System _DLL_InitTerm( sal_uInt32 nModule, + sal_uInt32 nFlag ) +{ + switch( nFlag ) + { + case 0: + { + /* initialize C runtime library */ + _CRT_init(); + { + LONG fhToAdd = 0; + ULONG fhOld = 0; + ULONG ngLastError = DosSetRelMaxFH(&fhToAdd, &fhOld); + if (fhOld < 200) + ngLastError = DosSetMaxFH(200); + } + + /* turn off hardware-errors and exception popups */ + DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION); + + break; + } + + case 1: + { + /* unload libs (sockets) */ + ImplFreeTCPIP(); + + /* unload libs (security) */ + ImplFreeUPM(); + + break; + } + } + + return (sal_True); +} +#endif + + diff --git a/sal/osl/os2/except.c b/sal/osl/os2/except.c new file mode 100644 index 000000000000..29962889fb01 --- /dev/null +++ b/sal/osl/os2/except.c @@ -0,0 +1,1059 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* + *@@sourcefile except.c: + * this file contains powerful exception handlers. + * except.h also defines easy-to-use macros for them. + * + * Usage: All OS/2 programs, PM or text mode. + * + * <B>Introduction</B> + * + * OS/2 exception handlers are a mess to program and, + * if installed wrongly, almost impossible to debug. + * The problem is that for any program that does a bit + * more than showing a message box, using exception + * handlers is a must to avoid system hangs. This + * especially applies to multi-thread programs using + * mutex semaphores (more on that below). The functions + * and macros in here are designed to make that more + * simple. + * + * The macros in except.h automatically insert code for + * properly registering and deregistering the handlers + * in except.c. You should ALWAYS use these macros + * instead of directly registering the handlers to avoid + * accidentally forgetting to deregister them. If you + * forget to deregister an exception handler, this can + * lead to really strange errors (crashes, hangs) which + * are nearly impossible to debug because the thread's + * stack probably got completely messed up. + * + * The general idea of these macros is to define + * TRY / CATCH blocks similar to C++. If an exception + * occurs in the TRY block, execution is transferred to + * the CATCH block. (This works in both C and C++, by the + * way.) + * + * The "OnKill" function that was added with V0.9.0 has + * been removed again with V0.9.7. + * + * The general usage is like this: + * + + int your_protected_func(int ...) + + { + + TRY_LOUD(excptid) // or: TRY_QUIET(excptid) + + { + + char *p = NULL; + + + + .... // the stuff in here is protected by + + // the excHandlerLoud or excHandlerQuiet + + // exception handler + + *p = "A"; + + } + + CATCH(excptid) + + { + + .... // exception occured: react here + + } END_CATCH(); // always needed! + + } // end of your_func + * + * TRY_LOUD is for installing excHandlerLoud. + * TRY_QUIET is for installing excHandlerQuiet. + * CATCH / END_CATCH are the same for the two. This + * is where the exception handler jumps to if an + * exception occurs. + * The CATCH block is _required_ even if you do nothing + * in there, because the CATCH() macro will deregister + * the handler. + * + * "excptid" can be any C identifier which is not used in + * your current variable scope, e.g. "excpt1". This + * is used for creating an EXCEPTSTRUCT variable of + * that name on the stack. The "excptid"'s in TRY_* and + * CATCH must match, since this is where the macros + * store the exception handler data. + * + * These macros may be nested if you use different + * "excptid"'s for sub-macros. + * + * Inside the TRY and CATCH blocks, you must not use + * "goto" (to a location outside the block) or "return", + * because this will not deregister the handler. + * + * Keep in mind that all the code in the TRY_* block is + * protected by the handler, including all functions that + * get called. So if you enclose your main() code in a + * TRY_* block, your entire application is protected. + * If any subfunction fails, execution is transferred to + * the closest CATCH() that was installed (as with C++ + * try and catch). + * + * <B>Asynchronous exceptions</B> + * + * The exception handlers in this file (which are installed + * with the TRY/CATCH mechanism) only intercept synchronous + * exceptions, most importantly, XCPT_ACCESS_VIOLATION (see + * excHandlerLoud for a list). They do not protect your code + * against asynchronous exceptions. + * + * OS/2 defines asynchronous exceptions to be those that + * can be delayed. With OS/2, there are only three of these: + * + * -- XCPT_PROCESS_TERMINATE + * -- XCPT_ASYNC_PROCESS_TERMINATE + * -- XCPT_SIGNAL (thread 1 only) + * + * To protect yourself against these also, put the section + * in question in a DosEnterMustComplete/DosExitMustComplete + * block as well. + * + * <B>Mutex semaphores</B> + * + * The problem with OS/2 mutex semaphores is that they are + * sometimes not automatically released when a thread terminates. + * If there are several mutexes involved and they are released + * in improper order, you can get zombie threads on exit. + * Even worse, if this happens to a PM thread, this will hang + * the system. + * + * As a result, you should protect any section of code which + * requests a semaphore with the exception handlers. + * + * So _whenever_ you request a mutex semaphore, enclose + * the block with TRY/CATCH in case the code crashes. + * Besides, enclose the TRY/CATCH block in a must-complete + * section, like this: + * + + HMTX hmtx = ... + + + + int your_func(int) + + { + + BOOL fSemOwned = FALSE; + + + + TRY_QUIET(excpt1) // or TRY_LOUD + + { + + if (fSemOwned = !DosRequestMutexSem(hmtx, ...)) + + { ... // work on your protected data + + } + + // mutex gets released below + + } + + CATCH(excpt1) { } END_CATCH(); // always needed! + + + + if (fSemOwned) + + // this gets executed always, even if an exception occured + + DosReleaseMutexSem(hmtx); + + } // end of your_func + * + * This way your mutex semaphore gets released in every + * possible condition. + * + * <B>Customizing</B> + * + * As opposed to versions before 0.9.0, this code is now + * completely independent of XWorkplace. This file now + * contains "pure" exception handlers only. + * + * However, you can customize these exception handlers by + * calling excRegisterHooks. This is what XWorkplace does now. + * This should be done upon initialization of your application. + * If excRegisterHooks is not called, the following safe + * defaults are used: + * + * -- the trap log file is TRAP.LOG in the root + * directory of your boot drive. + * + * For details on the provided exception handlers, refer + * to excHandlerLoud and excHandlerQuiet. + * + * More useful debug information can be found in the "OS/2 Debugging + * Handbook", which is now available in INF format on the IBM + * DevCon site ("http://service2.boulder.ibm.com/devcon/"). + * This book shows worked examples of how to unwind a stack dump. + * + * This file incorporates code from the following: + * -- Monte Copeland, IBM Boca Ration, Florida, USA (1993) + * -- Roman Stangl, from the Program Commander/2 sources + * (1997-98) + * -- Marc Fiammante, John Currier, Kim Rasmussen, + * Anthony Cruise (EXCEPT3.ZIP package for a generic + * exception handling DLL, available at Hobbes). + * + * If not explicitly stated otherwise, the code has been written + * by me, Ulrich M�ller. + * + * Note: Version numbering in this file relates to XWorkplace version + * numbering. + * + *@@header "helpers\except.h" + */ + +/* + * This file Copyright (C) 1992-99 Ulrich M�ller, + * Monte Copeland, + * Roman Stangl, + * Kim Rasmussen, + * Marc Fiammante, + * John Currier, + * Anthony Cruise. + * This file is part of the "XWorkplace helpers" source package. + * + * 2009-06-15 published under LGPL3 with Ulrich M�ller permission. + * + */ + +#define OS2EMX_PLAIN_CHAR + // this is needed for "os2emx.h"; if this is defined, + // emx will define PSZ as _signed_ char, otherwise + // as unsigned char + +#define INCL_DOSMODULEMGR +#define INCL_DOSEXCEPTIONS +#define INCL_DOSPROCESS +#define INCL_DOSMISC +#define INCL_DOSERRORS +#include <os2.h> + +// C library headers +#include <stdio.h> // needed for except.h +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <setjmp.h> // needed for except.h +#include <assert.h> // needed for except.h + +#define DONT_REPLACE_MALLOC +#include "helpers\setup.h" // code generation and debugging options + +// headers in /helpers +#include "helpers\dosh.h" // Control Program helper routines +#include "helpers\except.h" // exception handling +#include "helpers\debug.h" // symbol/debug code analysis + +#pragma hdrstop + +/* ****************************************************************** + * + * Global variables + * + ********************************************************************/ + +// hooks to be registered using excRegisterHooks +PFNEXCOPENFILE G_pfnExcOpenFile = 0; +PFNEXCHOOK G_pfnExcHook = 0; +PFNEXCHOOKERROR G_pfnExcHookError = 0; +// beep flag for excHandlerLoud +BOOL G_fBeepOnException = TRUE; + +ULONG G_ulExplainExceptionRunning = 0; + // global flag which is != 0 if some exception handler + // is inside excExplainException, so that XShutdown can + // wait until the trap log is done; + // this is exported thru except.h + // V0.9.13 (2001-06-19) [umoeller] + +/* + *@@category: Helpers\Control program helpers\Exceptions/debugging + * See except.c. + */ + +/* ****************************************************************** + * + * Exception helper routines + * + ********************************************************************/ + +/* + *@@ excDescribePage: + * + */ + +VOID excDescribePage(FILE *file, ULONG ulCheck) +{ + APIRET arc; + ULONG ulCountPages = 1; + ULONG ulFlagsPage = 0; + arc = DosQueryMem((PVOID)ulCheck, &ulCountPages, &ulFlagsPage); + + if (arc == NO_ERROR) + { + fprintf(file, "valid, flags: "); + if (ulFlagsPage & PAG_READ) + fprintf(file, "read "); + if (ulFlagsPage & PAG_WRITE) + fprintf(file, "write "); + if (ulFlagsPage & PAG_EXECUTE) + fprintf(file, "execute "); + if (ulFlagsPage & PAG_GUARD) + fprintf(file, "guard "); + if (ulFlagsPage & PAG_COMMIT) + fprintf(file, "committed "); + if (ulFlagsPage & PAG_SHARED) + fprintf(file, "shared "); + if (ulFlagsPage & PAG_FREE) + fprintf(file, "free "); + if (ulFlagsPage & PAG_BASE) + fprintf(file, "base "); + } + else if (arc == ERROR_INVALID_ADDRESS) + fprintf(file, "invalid"); +} + +/* + *@@ excPrintStackFrame: + * wrapper for dbgPrintStackFrame to format + * output stuff right. + * + *@@added V0.9.2 (2000-03-10) [umoeller] + *@@changed V0.9.12 (2001-05-12) [umoeller]: added seg:ofs to output always + */ + +VOID excPrintStackFrame(FILE *file, // in: output log file + PSZ pszDescription, // in: description for stack frame (should be eight chars) + ULONG ulAddress) // in: address to debug +{ + APIRET arc = NO_ERROR; + HMODULE hmod1 = NULLHANDLE; + CHAR szMod1[2*CCHMAXPATH] = "unknown"; + ULONG ulObject = 0, + ulOffset = 0; + fprintf(file, + " %-8s: %08lX ", + pszDescription, + ulAddress); + arc = DosQueryModFromEIP(&hmod1, + &ulObject, + sizeof(szMod1), szMod1, + &ulOffset, + ulAddress); + + if (arc != NO_ERROR) + { + // error: + fprintf(file, + " %-8s Error: DosQueryModFromEIP returned %lu\n", + szMod1, + arc); + } + else + { + CHAR szFullName[2*CCHMAXPATH]; + + fprintf(file, + " %-8s %02lX:%08lX\n ", + szMod1, + ulObject + 1, // V0.9.12 (2001-05-12) [umoeller] + ulOffset); // V0.9.12 (2001-05-12) [umoeller] + + DosQueryModuleName(hmod1, sizeof(szFullName), szFullName); + dbgPrintStackFrame(file, + szFullName, + ulObject, + ulOffset); + + fprintf(file, "\n"); + + // make a 'tick' sound to let the user know we're still alive + DosBeep(2000, 10); + } +} + +/* + *@@ excDumpStackFrames: + * called from excExplainException to dump the + * thread's stack frames. This calls excPrintStackFrame + * for each stack frame found. + * + *@@added V0.9.4 (2000-06-15) [umoeller] + */ + +VOID excDumpStackFrames(FILE *file, // in: logfile from fopen() + PTIB ptib, + PCONTEXTRECORD pContextRec) // in: excpt info +{ + PULONG pulStackWord = 0; + + fprintf(file, "\n\nStack frames:\n Address Module seg:ofs\n"); + + // first the trapping address itself + excPrintStackFrame(file, + "CS:EIP ", + pContextRec->ctx_RegEip); + + + pulStackWord = (PULONG)pContextRec->ctx_RegEbp; + /* if (pContextRec->ctx_RegEbp < pContextRec->ctx_RegEsp) + pulStackWord = (PULONG)(pContextRec->ctx_RegEbp & 0xFFFFFFF0); + else + pulStackWord = (PULONG)(pContextRec->ctx_RegEsp & 0xFFFFFFF0); */ + + while ( (pulStackWord != 0) + && (pulStackWord < (PULONG)ptib->tib_pstacklimit) + ) + { + CHAR szAddress[20]; + + if (((ULONG)pulStackWord & 0x00000FFF) == 0x00000000) + { + // we're on a page boundary: check access + ULONG ulCountPages = 0x1000; + ULONG ulFlagsPage = 0; + APIRET arc = DosQueryMem((void *)pulStackWord, + &ulCountPages, + &ulFlagsPage); + if ( (arc != NO_ERROR) + || ( (arc == NO_ERROR) + && ( !( ((ulFlagsPage & (PAG_COMMIT|PAG_READ)) + == (PAG_COMMIT|PAG_READ) + ) + ) + ) + ) + ) + { + fprintf(file, "\n %08lX: ", (ULONG)pulStackWord); + fprintf(file, "Page inaccessible"); + pulStackWord += 0x1000; + continue; // for + } + } + + sprintf(szAddress, "%08lX", + (ULONG)pulStackWord); + excPrintStackFrame(file, + szAddress, + *(pulStackWord+1)); + pulStackWord = (PULONG)*(pulStackWord); + + if (pulStackWord == 0) + fprintf(file, "\n pulStackWord == 0"); + else if (pulStackWord >= (PULONG)ptib->tib_pstacklimit) + fprintf(file, "\n pulStackWord >= (PULONG)ptib->tib_pstacklimit"); + } // end while +} + +/* + *@@ excExplainException: + * used by the exception handlers below to write + * LOTS of information about the exception into a logfile. + * + * This calls excPrintStackFrame for each stack frame. + * + *@@changed V0.9.0 [umoeller]: added support for application hook + *@@changed V0.9.0 (99-11-02) [umoeller]: added TID to dump + *@@changed V0.9.2 (2000-03-10) [umoeller]: now using excPrintStackFrame + *@@changed V0.9.3 (2000-05-03) [umoeller]: fixed crashes + *@@changed V0.9.6 (2000-11-06) [umoeller]: added more register dumps + *@@changed V0.9.13 (2001-06-19) [umoeller]: added global flag for whether this is running + *@@changed V0.9.16 (2001-11-02) [pr]: make object display signed + *@@changed V0.9.19 (2002-03-28) [umoeller]: added thread ordinal + */ + +VOID excExplainException(FILE *file, // in: logfile from fopen() + PSZ pszHandlerName, // in: descriptive string + PEXCEPTIONREPORTRECORD pReportRec, // in: excpt info + PCONTEXTRECORD pContextRec) // in: excpt info +{ + ULONG aulBuf[3]; + const char *pcszVersion = "unknown"; + + PTIB ptib = NULL; + PPIB ppib = NULL; + HMODULE hMod1, hMod2; + CHAR szMod1[CCHMAXPATH] = "unknown", + szMod2[CCHMAXPATH] = "unknown"; + ULONG ulObjNum, + ulOffset; + ULONG ul; + + ULONG ulOldPriority = 0x0100; // regular, delta 0 + + // raise global flag for whether this func is running + // V0.9.13 (2001-06-19) [umoeller] + G_ulExplainExceptionRunning++; + + // raise this thread's priority, because this + // might take some time + if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR) + if (ptib) + if (ptib->tib_ptib2) + { + ulOldPriority = ptib->tib_ptib2->tib2_ulpri; + DosSetPriority(PRTYS_THREAD, + PRTYC_REGULAR, + PRTYD_MAXIMUM, + 0); // current thread + } + + // make some noise +#ifndef __NOEXCEPTIONBEEPS__ // V0.9.19 (2002-04-17) [umoeller] + if (G_fBeepOnException) + { + DosBeep( 250, 30); + DosBeep( 500, 30); + DosBeep(1000, 30); + DosBeep(2000, 30); + DosBeep(4000, 30); + DosBeep(2000, 30); + DosBeep(1000, 30); + DosBeep( 500, 30); + DosBeep( 250, 30); + } +#endif + + // generic exception info + DosQuerySysInfo(QSV_VERSION_MAJOR, // 11 + QSV_VERSION_MINOR, // 12 + &aulBuf, sizeof(aulBuf)); + // Warp 3 is reported as 20.30 + // Warp 4 is reported as 20.40 + // Aurora is reported as 20.45 + + if (aulBuf[0] == 20) + { + switch (aulBuf[1]) + { + case 30: pcszVersion = "Warp 3"; break; + case 40: pcszVersion = "Warp 4"; break; + case 45: pcszVersion = "WSeB kernel"; break; + } + } + fprintf(file, + "Running OS/2 version: %u.%u (%s)\n", + aulBuf[0], // major + aulBuf[1], + pcszVersion); + + + // generic exception info + fprintf(file, + "\n%s:\n Exception type: %08lX\n Address: %08lX\n Params: ", + pszHandlerName, + pReportRec->ExceptionNum, + (ULONG)pReportRec->ExceptionAddress); + for (ul = 0; ul < pReportRec->cParameters; ul++) + { + fprintf(file, "%08lX ", + pReportRec->ExceptionInfo[ul]); + } + + // now explain the exception in a bit more detail; + // depending on the exception, pReportRec->ExceptionInfo + // contains some useful data + switch (pReportRec->ExceptionNum) + { + case XCPT_ACCESS_VIOLATION: + fprintf(file, "\nXCPT_ACCESS_VIOLATION: "); + if (pReportRec->ExceptionInfo[0] & XCPT_READ_ACCESS) + fprintf(file, "Invalid read access from 0x%04lX:%08lX.\n", + pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]); + else if (pReportRec->ExceptionInfo[0] & XCPT_WRITE_ACCESS) + fprintf(file, "Invalid write access to 0x%04lX:%08lX.\n", + pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]); + else if (pReportRec->ExceptionInfo[0] & XCPT_SPACE_ACCESS) + fprintf(file, "Invalid space access at 0x%04lX.\n", + pReportRec->ExceptionInfo[1]); + else if (pReportRec->ExceptionInfo[0] & XCPT_LIMIT_ACCESS) + fprintf(file, "Invalid limit access occurred.\n"); + else if (pReportRec->ExceptionInfo[0] == XCPT_UNKNOWN_ACCESS) + fprintf(file, "unknown at 0x%04lX:%08lX\n", + pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]); + fprintf(file, + "Explanation: An attempt was made to access a memory object which does\n" + " not belong to the current process. Most probable causes\n" + " for this are that an invalid pointer was used, there was\n" + " confusion with administering memory or error conditions \n" + " were not properly checked for.\n"); + break; + + case XCPT_INTEGER_DIVIDE_BY_ZERO: + fprintf(file, "\nXCPT_INTEGER_DIVIDE_BY_ZERO.\n"); + fprintf(file, + "Explanation: An attempt was made to divide an integer value by zero,\n" + " which is not defined.\n"); + break; + + case XCPT_ILLEGAL_INSTRUCTION: + fprintf(file, "\nXCPT_ILLEGAL_INSTRUCTION.\n"); + fprintf(file, + "Explanation: An attempt was made to execute an instruction that\n" + " is not defined on this machine's architecture.\n"); + break; + + case XCPT_PRIVILEGED_INSTRUCTION: + fprintf(file, "\nXCPT_PRIVILEGED_INSTRUCTION.\n"); + fprintf(file, + "Explanation: An attempt was made to execute an instruction that\n" + " is not permitted in the current machine mode or that\n" + " the program had no permission to execute.\n"); + break; + + case XCPT_INTEGER_OVERFLOW: + fprintf(file, "\nXCPT_INTEGER_OVERFLOW.\n"); + fprintf(file, + "Explanation: An integer operation generated a carry-out of the most\n" + " significant bit. This is a sign of an attempt to store\n" + " a value which does not fit into an integer variable.\n"); + break; + + default: + fprintf(file, "\nUnknown OS/2 exception number %d.\n", pReportRec->ExceptionNum); + fprintf(file, "Look this up in the OS/2 header files.\n"); + break; + } + + // V0.9.16 (2001-11-02) [pr]: We already got this info. above - this overwrites the + // original values before the priority change, which is rather confusing. + // if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR) + { + /* + * process info: + * + */ + + if ((ptib) && (ppib)) // (99-11-01) [umoeller] + { + if (pContextRec->ContextFlags & CONTEXT_CONTROL) + { + // get the main module + hMod1 = ppib->pib_hmte; + DosQueryModuleName(hMod1, + sizeof(szMod1), + szMod1); + + // get the trapping module + DosQueryModFromEIP(&hMod2, + &ulObjNum, + sizeof(szMod2), + szMod2, + &ulOffset, + pContextRec->ctx_RegEip); + DosQueryModuleName(hMod2, + sizeof(szMod2), + szMod2); + } + + fprintf(file, + "\nProcess information:" + "\n Process ID: 0x%lX" + "\n Process module: 0x%lX (%s)" + "\n Trapping module: 0x%lX (%s)" + "\n Object: %ld\n", // V0.9.16 (2001-11-02) [pr]: make this display signed + ppib->pib_ulpid, + hMod1, szMod1, + hMod2, szMod2, + ulObjNum); + + fprintf(file, + "\nTrapping thread information:" + "\n Thread ID: 0x%lX (%lu)" + "\n Thread slot ID: 0x%lX (%lu)" // added V0.9.19 (2002-03-28) [umoeller] + "\n Priority: 0x%lX\n", + ptib->tib_ptib2->tib2_ultid, ptib->tib_ptib2->tib2_ultid, + ptib->tib_ordinal, ptib->tib_ordinal, + ulOldPriority); + } + else + fprintf(file, "\nProcess information was not available."); + + /* + * now call the hook, if one has been defined, + * so that the application can write additional + * information to the traplog (V0.9.0) + */ + + if (G_pfnExcHook) + G_pfnExcHook(file, ptib, ulOldPriority); // V0.9.16 (2001-12-02) [pr] + + // *** registers + + fprintf(file, "\nRegisters:"); + if (pContextRec->ContextFlags & CONTEXT_INTEGER) + { + // DS the following 4 added V0.9.6 (2000-11-06) [umoeller] + fprintf(file, "\n DS = %08lX ", pContextRec->ctx_SegDs); + excDescribePage(file, pContextRec->ctx_SegDs); + // ES + fprintf(file, "\n ES = %08lX ", pContextRec->ctx_SegEs); + excDescribePage(file, pContextRec->ctx_SegEs); + // FS + fprintf(file, "\n FS = %08lX ", pContextRec->ctx_SegFs); + excDescribePage(file, pContextRec->ctx_SegFs); + // GS + fprintf(file, "\n GS = %08lX ", pContextRec->ctx_SegGs); + excDescribePage(file, pContextRec->ctx_SegGs); + + // EAX + fprintf(file, "\n EAX = %08lX ", pContextRec->ctx_RegEax); + excDescribePage(file, pContextRec->ctx_RegEax); + // EBX + fprintf(file, "\n EBX = %08lX ", pContextRec->ctx_RegEbx); + excDescribePage(file, pContextRec->ctx_RegEbx); + // ECX + fprintf(file, "\n ECX = %08lX ", pContextRec->ctx_RegEcx); + excDescribePage(file, pContextRec->ctx_RegEcx); + // EDX + fprintf(file, "\n EDX = %08lX ", pContextRec->ctx_RegEdx); + excDescribePage(file, pContextRec->ctx_RegEdx); + // ESI + fprintf(file, "\n ESI = %08lX ", pContextRec->ctx_RegEsi); + excDescribePage(file, pContextRec->ctx_RegEsi); + // EDI + fprintf(file, "\n EDI = %08lX ", pContextRec->ctx_RegEdi); + excDescribePage(file, pContextRec->ctx_RegEdi); + fprintf(file, "\n"); + } + else + fprintf(file, " not available\n"); + + if (pContextRec->ContextFlags & CONTEXT_CONTROL) + { + + // *** instruction + + fprintf(file, "Instruction pointer (where exception occured):\n CS:EIP = %04lX:%08lX ", + pContextRec->ctx_SegCs, + pContextRec->ctx_RegEip); + excDescribePage(file, pContextRec->ctx_RegEip); + + // *** CPU flags + + fprintf(file, "\n EFLAGS = %08lX", pContextRec->ctx_EFlags); + + /* + * stack: + * + */ + + fprintf(file, "\nStack:\n Base: %08lX\n Limit: %08lX", + (ULONG)(ptib ? ptib->tib_pstack : 0), + (ULONG)(ptib ? ptib->tib_pstacklimit : 0)); + fprintf(file, "\n SS:ESP = %04lX:%08lX ", + pContextRec->ctx_SegSs, + pContextRec->ctx_RegEsp); + excDescribePage(file, pContextRec->ctx_RegEsp); + + fprintf(file, "\n EBP = %08lX ", pContextRec->ctx_RegEbp); + excDescribePage(file, pContextRec->ctx_RegEbp); + + /* + * stack dump: + */ + + if (ptib != 0) + { + excDumpStackFrames(file, ptib, pContextRec); + } + } + } + fprintf(file, "\n"); + + // reset old priority + DosSetPriority(PRTYS_THREAD, + (ulOldPriority & 0x0F00) >> 8, + (UCHAR)ulOldPriority, + 0); // current thread + + // lower global flag again V0.9.13 (2001-06-19) [umoeller] + G_ulExplainExceptionRunning--; +} + +/* ****************************************************************** + * + * Exported routines + * + ********************************************************************/ + +/* + *@@ excRegisterHooks: + * this registers hooks which get called for + * exception handlers. You can set any of the + * hooks to NULL for safe defaults (see top of + * except.c for details). You can set none, + * one, or both of the hooks, and you can call + * this function several times. + * + * Both hooks get called whenever an exception + * occurs, so there better be no bugs in these + * routines. ;-) They only get called from + * within excHandlerLoud (because excHandlerQuiet + * writes no trap logs). + * + * The hooks are as follows: + * + * -- pfnExcOpenFileNew gets called to open + * the trap log file. This must return a FILE* + * pointer from fopen(). If this is not defined, + * ?:\TRAP.LOG is used. Use this to specify a + * different file and have some notes written + * into it before the actual exception info. + * + * -- pfnExcHookNew gets called while the trap log + * is being written. At this point, + * the following info has been written into + * the trap log already: + * -- exception type/address block + * -- exception explanation + * -- process information + * + * _After_ the hook, the exception handler + * continues with the "Registers" information + * and stack dump/analysis. + * + * Use this hook to write additional application + * info into the trap log, such as the state + * of your own threads and mutexes. + * + * -- pfnExcHookError gets called when the TRY_* macros + * fail to install an exception handler (when + * DosSetExceptionHandler fails). I've never seen + * this happen. + * + *@@added V0.9.0 [umoeller] + *@@changed V0.9.2 (2000-03-10) [umoeller]: pfnExcHookError added + */ + +VOID excRegisterHooks(PFNEXCOPENFILE pfnExcOpenFileNew, + PFNEXCHOOK pfnExcHookNew, + PFNEXCHOOKERROR pfnExcHookError, + BOOL fBeepOnExceptionNew) +{ + // adjust the global variables + G_pfnExcOpenFile = pfnExcOpenFileNew; + G_pfnExcHook = pfnExcHookNew; + G_pfnExcHookError = pfnExcHookError; + G_fBeepOnException = fBeepOnExceptionNew; +} + +/* + *@@ excHandlerLoud: + * this is the "sophisticated" exception handler; + * which gives forth a loud sequence of beeps thru the + * speaker, writes a trap log and then returns back + * to the thread to continue execution, i.e. the + * default OS/2 exception handler will never get + * called. + * + * This requires a setjmp() call on + * EXCEPTIONREGISTRATIONRECORD2.jmpThread before + * being installed. The TRY_LOUD macro will take + * care of this for you (see except.c). + * + * This intercepts the following exceptions (see + * the OS/2 Control Program Reference for details): + * + * -- XCPT_ACCESS_VIOLATION (traps 0x0d, 0x0e) + * -- XCPT_INTEGER_DIVIDE_BY_ZERO (trap 0) + * -- XCPT_ILLEGAL_INSTRUCTION (trap 6) + * -- XCPT_PRIVILEGED_INSTRUCTION + * -- XCPT_INTEGER_OVERFLOW (trap 4) + * + * For these exceptions, we call the functions in debug.c + * to try to find debug code or SYM file information about + * what source code corresponds to the error. + * + * See excRegisterHooks for the default setup of this. + * + * Note that to get meaningful debugging information + * in this handler's traplog, you need the following: + * + * a) have a MAP file created at link time (/MAP) + * + * b) convert the MAP to a SYM file using MAPSYM + * + * c) put the SYM file in the same directory of + * the module (EXE or DLL). This must have the + * same filestem as the module. + * + * All other exceptions are passed to the next handler + * in the exception handler chain. This might be the + * C/C++ compiler handler or the default OS/2 handler, + * which will probably terminate the process. + * + *@@changed V0.9.0 [umoeller]: added support for thread termination + *@@changed V0.9.2 (2000-03-10) [umoeller]: switched date format to ISO + *@@changed V0.9.19 (2002-05-07) [umoeller]: added EXCEPTIONREPORTRECORD info so that catch block can check that + */ + +ULONG _System excHandlerLoud(PEXCEPTIONREPORTRECORD pReportRec, + PEXCEPTIONREGISTRATIONRECORD2 pRegRec2, + PCONTEXTRECORD pContextRec, + PVOID pv) +{ + /* From the VAC++3 docs: + * "The first thing an exception handler should do is check the + * exception flags. If EH_EXIT_UNWIND is set, meaning + * the thread is ending, the handler tells the operating system + * to pass the exception to the next exception handler. It does the + * same if the EH_UNWINDING flag is set, the flag that indicates + * this exception handler is being removed. + * The EH_NESTED_CALL flag indicates whether the exception + * occurred within an exception handler. If the handler does + * not check this flag, recursive exceptions could occur until + * there is no stack remaining." + * So for all these conditions, we exit immediately. + */ + + if (pReportRec->fHandlerFlags & EH_EXIT_UNWIND) + return (XCPT_CONTINUE_SEARCH); + if (pReportRec->fHandlerFlags & EH_UNWINDING) + return (XCPT_CONTINUE_SEARCH); + if (pReportRec->fHandlerFlags & EH_NESTED_CALL) + return (XCPT_CONTINUE_SEARCH); + + switch (pReportRec->ExceptionNum) + { + case XCPT_ACCESS_VIOLATION: + case XCPT_INTEGER_DIVIDE_BY_ZERO: + case XCPT_ILLEGAL_INSTRUCTION: + case XCPT_PRIVILEGED_INSTRUCTION: + case XCPT_INVALID_LOCK_SEQUENCE: + case XCPT_INTEGER_OVERFLOW: + { + // "real" exceptions: + FILE *file; + + // open traplog file; + if (G_pfnExcOpenFile) + // hook defined for this: call it + file = (*G_pfnExcOpenFile)(); + else + { + CHAR szFileName[100]; + // no hook defined: open some + // default traplog file in root directory of + // boot drive + sprintf(szFileName, "%c:\\trap.log", doshQueryBootDrive()); + file = fopen(szFileName, "a"); + + if (file) + { + DATETIME DT; + DosGetDateTime(&DT); + fprintf(file, + "\nTrap message -- Date: %04d-%02d-%02d, Time: %02d:%02d:%02d\n", + DT.year, DT.month, DT.day, + DT.hours, DT.minutes, DT.seconds); + fprintf(file, "------------------------------------------------\n"); + + } + } + + // write error log + excExplainException(file, + "excHandlerLoud", + pReportRec, + pContextRec); + fclose(file); + + // copy report rec to user buffer + // V0.9.19 (2002-05-07) [umoeller] + memcpy(&pRegRec2->err, + pReportRec, + sizeof(EXCEPTIONREPORTRECORD)); + + // jump back to failing routine + longjmp(pRegRec2->jmpThread, pReportRec->ExceptionNum); + break; } + } + + // not handled + return (XCPT_CONTINUE_SEARCH); +} + +/* + *@@ excHandlerQuiet: + * "quiet" xcpt handler, which simply suppresses exceptions; + * this is useful for certain error-prone functions, where + * exceptions are likely to appear, for example used by + * wpshCheckObject to implement a fail-safe SOM object check. + * + * This does _not_ write an error log and makes _no_ sound. + * This simply jumps back to the trapping thread or + * calls EXCEPTIONREGISTRATIONRECORD2.pfnOnKill. + * + * Other than that, this behaves like excHandlerLoud. + * + * This is best registered thru the TRY_QUIET macro + * (new with V0.84, described in except.c), which + * does the necessary setup. + * + *@@changed V0.9.0 [umoeller]: added support for thread termination + *@@changed V0.9.19 (2002-05-07) [umoeller]: added EXCEPTIONREPORTRECORD info so that catch block can check that + */ + +ULONG _System excHandlerQuiet(PEXCEPTIONREPORTRECORD pReportRec, + PEXCEPTIONREGISTRATIONRECORD2 pRegRec2, + PCONTEXTRECORD pContextRec, + PVOID pv) +{ + if (pReportRec->fHandlerFlags & EH_EXIT_UNWIND) + return (XCPT_CONTINUE_SEARCH); + if (pReportRec->fHandlerFlags & EH_UNWINDING) + return (XCPT_CONTINUE_SEARCH); + if (pReportRec->fHandlerFlags & EH_NESTED_CALL) + return (XCPT_CONTINUE_SEARCH); + + switch (pReportRec->ExceptionNum) + { + case XCPT_ACCESS_VIOLATION: + case XCPT_INTEGER_DIVIDE_BY_ZERO: + case XCPT_ILLEGAL_INSTRUCTION: + case XCPT_PRIVILEGED_INSTRUCTION: + case XCPT_INVALID_LOCK_SEQUENCE: + case XCPT_INTEGER_OVERFLOW: + // write excpt explanation only if the + // resp. debugging #define is set (setup.h) + #ifdef DEBUG_WRITEQUIETEXCPT + { + FILE *file = excOpenTraplogFile(); + excExplainException(file, + "excHandlerQuiet", + pReportRec, + pContextRec); + fclose(file); + } + #endif + + // copy report rec to user buffer + // V0.9.19 (2002-05-07) [umoeller] + memcpy(&pRegRec2->err, + pReportRec, + sizeof(EXCEPTIONREPORTRECORD)); + + // jump back to failing routine + longjmp(pRegRec2->jmpThread, pReportRec->ExceptionNum); + break; + + default: + break; + } + + return (XCPT_CONTINUE_SEARCH); +} + + diff --git a/sal/osl/os2/file.cxx b/sal/osl/os2/file.cxx new file mode 100644 index 000000000000..2e668d23d638 --- /dev/null +++ b/sal/osl/os2/file.cxx @@ -0,0 +1,3129 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 + +#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; + } + +/****************************************************************************** + * + * 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 + ***************************************************************************/ + +oslFileHandle osl_createFileHandleFromFD( int fd ) +{ + oslFileHandleImpl* pHandleImpl = NULL; + + if ( fd >= 0 ) + { + pHandleImpl = (oslFileHandleImpl*) rtl_allocateMemory( sizeof(oslFileHandleImpl) ); + + if( pHandleImpl ) + { + pHandleImpl->ustrFilePath = NULL; + rtl_uString_new( &pHandleImpl->ustrFilePath ); + pHandleImpl->fd = fd; + + /* FIXME: should detect whether the file has been locked */ + pHandleImpl->bLocked = sal_True; + } + } + + return (oslFileHandle)pHandleImpl; +} + +/**************************************************************************** + * osl_openFile + ***************************************************************************/ + +oslFileError osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags ) +{ + oslFileHandleImpl* pHandleImpl = NULL; + oslFileError eRet; + rtl_uString* ustrFilePath = NULL; + + char buffer[PATH_MAX]; + int fd; + int mode = S_IRUSR | S_IRGRP | S_IROTH; + int flags = O_RDONLY; + + struct flock aflock; + + /* locking the complete file */ + aflock.l_type = 0; + aflock.l_whence = SEEK_SET; + aflock.l_start = 0; + aflock.l_len = 0; + + OSL_ASSERT( ustrFileURL ); + OSL_ASSERT( pHandle ); + + if( ( 0 == ustrFileURL->length ) ) + return osl_File_E_INVAL; + + /* convert file URL to system path */ + eRet = osl_getSystemPathFromFileURL( ustrFileURL, &ustrFilePath ); + + if( osl_File_E_None != eRet ) + return eRet; + + osl_systemPathRemoveSeparator(ustrFilePath); + + /* convert unicode path to text */ + if( UnicodeToText( buffer, PATH_MAX, ustrFilePath->buffer, ustrFilePath->length ) ) + { + /* we do not open devices or such here */ + if( !( uFlags & osl_File_OpenFlag_Create ) ) + { + struct stat aFileStat; + + if( 0 > stat( buffer, &aFileStat ) ) + { + PERROR( "osl_openFile", buffer ); + eRet = oslTranslateFileError(OSL_FET_ERROR, errno ); + } + + else if( !S_ISREG( aFileStat.st_mode ) ) + { + eRet = osl_File_E_INVAL; + } + } + + if( osl_File_E_None == eRet ) + { + /* + * set flags and mode + */ + + if ( uFlags & osl_File_OpenFlag_Write ) + { + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + flags = O_RDWR; + aflock.l_type = F_WRLCK; + } + + if ( uFlags & osl_File_OpenFlag_Create ) + { + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + flags = O_CREAT | O_EXCL | O_RDWR; + } + + /* open the file */ + fd = open( buffer, flags | O_BINARY, mode); + if ( fd >= 0 ) + { + sal_Bool bNeedsLock = ( ( uFlags & osl_File_OpenFlag_NoLock ) == 0 ); + sal_Bool bLocked = sal_False; + if( bNeedsLock ) + { + /* check if file lock is enabled and clear l_type member of flock otherwise */ + if( (char *) -1 == pFileLockEnvVar ) + { + /* FIXME: this is not MT safe */ + pFileLockEnvVar = getenv("SAL_ENABLE_FILE_LOCKING"); + + if( NULL == pFileLockEnvVar) + pFileLockEnvVar = getenv("STAR_ENABLE_FILE_LOCKING"); + } + + if( NULL == pFileLockEnvVar ) + aflock.l_type = 0; + + /* lock the file if flock.l_type is set */ + bLocked = ( F_WRLCK != aflock.l_type || -1 != fcntl( fd, F_SETLK, &aflock ) ); + } + + if ( !bNeedsLock || bLocked ) + { + /* allocate memory for impl structure */ + pHandleImpl = (oslFileHandleImpl*) rtl_allocateMemory( sizeof(oslFileHandleImpl) ); + if( pHandleImpl ) + { + pHandleImpl->ustrFilePath = ustrFilePath; + pHandleImpl->fd = fd; + pHandleImpl->bLocked = bLocked; + + *pHandle = (oslFileHandle) pHandleImpl; + + return osl_File_E_None; + } + else + { + errno = ENOMEM; + } + } + + close( fd ); + } + + PERROR( "osl_openFile", buffer ); + eRet = oslTranslateFileError(OSL_FET_ERROR, errno ); + } + } + else + eRet = osl_File_E_INVAL; + + rtl_uString_release( ustrFilePath ); + return eRet; +} + +/****************************************************************************/ +/* osl_closeFile */ +/****************************************************************************/ + +oslFileError osl_closeFile( oslFileHandle Handle ) +{ + oslFileHandleImpl* pHandleImpl = (oslFileHandleImpl *) Handle; + oslFileError eRet = osl_File_E_INVAL; + + OSL_ASSERT( Handle ); + + if( pHandleImpl ) + { + rtl_uString_release( pHandleImpl->ustrFilePath ); + + /* release file lock if locking is enabled */ + if( pFileLockEnvVar ) + { + struct flock aflock; + + aflock.l_type = F_UNLCK; + aflock.l_whence = SEEK_SET; + aflock.l_start = 0; + aflock.l_len = 0; + + if ( pHandleImpl->bLocked ) + { + /* FIXME: check if file is really locked ? */ + + /* release the file share lock on this file */ + if( -1 == fcntl( pHandleImpl->fd, F_SETLK, &aflock ) ) + PERROR( "osl_closeFile", "unlock failed" ); + } + } + + if( 0 > close( pHandleImpl->fd ) ) + { + eRet = oslTranslateFileError(OSL_FET_ERROR, errno ); + } + else + eRet = osl_File_E_None; + + rtl_freeMemory( pHandleImpl ); + } + + return eRet; +} + +/****************************************************************************/ +/* osl_isEndOfFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF ) +{ + oslFileHandleImpl* pHandleImpl = (oslFileHandleImpl *) Handle; + oslFileError eRet = osl_File_E_INVAL; + + if ( pHandleImpl) + { + long curPos = lseek( pHandleImpl->fd, 0, SEEK_CUR ); + + if ( curPos >= 0 ) + { + long endPos = lseek( pHandleImpl->fd, 0, SEEK_END ); + + if ( endPos >= 0 ) + { + *pIsEOF = ( curPos == endPos ); + curPos = lseek( pHandleImpl->fd, curPos, SEEK_SET ); + + if ( curPos >= 0 ) + eRet = osl_File_E_None; + else + eRet = oslTranslateFileError(OSL_FET_ERROR, errno ); + } + else + eRet = oslTranslateFileError(OSL_FET_ERROR, errno ); + } + else + eRet = oslTranslateFileError(OSL_FET_ERROR, errno ); + } + + return eRet; +} + + +/****************************************************************************/ +/* 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 > 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) + * + *****************************************************************************/ + + +/******************************************* + osl_readFile +********************************************/ + +oslFileError osl_readFile(oslFileHandle Handle, void* pBuffer, sal_uInt64 uBytesRequested, sal_uInt64* pBytesRead) +{ + ssize_t nBytes = 0; + oslFileHandleImpl* pHandleImpl = (oslFileHandleImpl*)Handle; + + if ((0 == pHandleImpl) || (pHandleImpl->fd < 0) || (0 == pBuffer) || (0 == pBytesRead)) + return osl_File_E_INVAL; + + nBytes = read(pHandleImpl->fd, pBuffer, uBytesRequested); + + if (-1 == nBytes) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + *pBytesRead = nBytes; + return osl_File_E_None; +} + +/******************************************* + osl_writeFile +********************************************/ + +oslFileError osl_writeFile(oslFileHandle Handle, const void* pBuffer, sal_uInt64 uBytesToWrite, sal_uInt64* pBytesWritten) +{ + ssize_t nBytes = 0; + oslFileHandleImpl* pHandleImpl = (oslFileHandleImpl*)Handle; + + OSL_ASSERT(pHandleImpl); + OSL_ASSERT(pBuffer); + OSL_ASSERT(pBytesWritten); + + if ((0 == pHandleImpl) || (0 == pBuffer) || (0 == pBytesWritten)) + return osl_File_E_INVAL; + + OSL_ASSERT(pHandleImpl->fd >= 0); + + if (pHandleImpl->fd < 0) + return osl_File_E_INVAL; + + nBytes = write(pHandleImpl->fd, pBuffer, uBytesToWrite); + + if (-1 == nBytes) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + *pBytesWritten = nBytes; + return osl_File_E_None; +} + +/******************************************* + osl_writeFile +********************************************/ + +oslFileError osl_setFilePos( oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uPos ) +{ + oslFileHandleImpl* pHandleImpl=0; + int nRet=0; + off_t nOffset=0; + + pHandleImpl = (oslFileHandleImpl*) Handle; + if ( pHandleImpl == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pHandleImpl->fd < 0 ) + { + return osl_File_E_INVAL; + } + + /* FIXME mfe: setFilePos: Do we have any runtime function to determine LONG_MAX? */ + if ( uPos > LONG_MAX ) + { + return osl_File_E_OVERFLOW; + } + + nOffset=(off_t)uPos; + + switch(uHow) + { + case osl_Pos_Absolut: + nOffset = lseek(pHandleImpl->fd,nOffset,SEEK_SET); + break; + + case osl_Pos_Current: + nOffset = lseek(pHandleImpl->fd,nOffset,SEEK_CUR); + break; + + case osl_Pos_End: + nOffset = lseek(pHandleImpl->fd,nOffset,SEEK_END); + break; + + default: + return osl_File_E_INVAL; + } + + if ( nOffset < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/************************************************ + * osl_getFilePos + ***********************************************/ + +oslFileError osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos ) +{ + oslFileHandleImpl* pHandleImpl=0; + off_t nOffset=0; + int nRet=0; + + pHandleImpl = (oslFileHandleImpl*) Handle; + if ( pHandleImpl == 0 || pPos == 0) + { + return osl_File_E_INVAL; + } + + if ( pHandleImpl->fd < 0 ) + { + return osl_File_E_INVAL; + } + + nOffset = lseek(pHandleImpl->fd,0,SEEK_CUR); + + if (nOffset < 0) + { + nRet =errno; + + /* *pPos =0; */ + + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + *pPos=nOffset; + + return osl_File_E_None; +} + +/**************************************************************************** + * osl_getFileSize + ****************************************************************************/ + +oslFileError osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize ) +{ + oslFileHandleImpl* pHandleImpl=(oslFileHandleImpl*) Handle; + if (pHandleImpl == 0) + return osl_File_E_INVAL; + + struct stat file_stat; + if (fstat(pHandleImpl->fd, &file_stat) == -1) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + *pSize = file_stat.st_size; + return osl_File_E_None; +} + +/************************************************ + * osl_setFileSize + ***********************************************/ + +oslFileError osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize ) +{ + oslFileHandleImpl* pHandleImpl=0; + off_t nOffset=0; + + pHandleImpl = (oslFileHandleImpl*) Handle; + if ( pHandleImpl == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pHandleImpl->fd < 0 ) + { + return osl_File_E_INVAL; + } + + /* FIXME: mfe: setFileSize: Do we have any runtime function to determine LONG_MAX? */ + if ( uSize > LONG_MAX ) + { + return osl_File_E_OVERFLOW; + } + + nOffset = (off_t)uSize; + if (ftruncate (pHandleImpl->fd, nOffset) < 0) + { + /* Failure. Try fallback algorithm */ + oslFileError result; + struct stat aStat; + off_t nCurPos; + + /* Save original result */ + result = oslTranslateFileError (OSL_FET_ERROR, errno); + PERROR("ftruncate", "Try osl_setFileSize [fallback]\n"); + + /* Check against current size. Fail upon 'shrink' */ + if (fstat (pHandleImpl->fd, &aStat) < 0) + { + PERROR("ftruncate: fstat", "Out osl_setFileSize [error]\n"); + return (result); + } + if ((0 <= nOffset) && (nOffset <= aStat.st_size)) + { + /* Failure upon 'shrink'. Return original result */ + return (result); + } + + /* Save current position */ + nCurPos = (off_t)lseek (pHandleImpl->fd, (off_t)0, SEEK_CUR); + if (nCurPos == (off_t)(-1)) + { + PERROR("ftruncate: lseek", "Out osl_setFileSize [error]\n"); + return (result); + } + + /* Try 'expand' via 'lseek()' and 'write()' */ + if (lseek (pHandleImpl->fd, (off_t)(nOffset - 1), SEEK_SET) < 0) + { + PERROR("ftruncate: lseek", "Out osl_setFileSize [error]\n"); + return (result); + } + if (write (pHandleImpl->fd, (char*)"", (size_t)1) < 0) + { + /* Failure. Restore saved position */ + PERROR("ftruncate: write", "Out osl_setFileSize [error]\n"); + if (lseek (pHandleImpl->fd, (off_t)nCurPos, SEEK_SET) < 0) + { +#ifdef DEBUG_OSL_FILE + perror("ftruncate: lseek"); +#endif /* DEBUG_OSL_FILE */ + } + return (result); + } + + /* Success. Restore saved position */ + if (lseek (pHandleImpl->fd, (off_t)nCurPos, SEEK_SET) < 0) + { + PERROR("ftruncate: lseek", "Out osl_setFileSize [error]"); + return (result); + } + } + + return (osl_File_E_None); +} + +/*###############################################*/ +oslFileError SAL_CALL osl_syncFile(oslFileHandle Handle) +{ + oslFileHandleImpl* handle_impl = (oslFileHandleImpl*)Handle; + + if (handle_impl == 0) + return osl_File_E_INVAL; + + if (fsync(handle_impl->fd) == -1) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + return osl_File_E_None; +} + +/****************************************************************************** + * + * C-String Versions of Exported Module Functions + * + *****************************************************************************/ + +#ifdef HAVE_STATFS_H + +#if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) +# define __OSL_STATFS_STRUCT struct statfs +# define __OSL_STATFS(dir, sfs) statfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_bsize)) +# define __OSL_STATFS_TYPENAME(a) ((a).f_fstypename) +# define __OSL_STATFS_ISREMOTE(a) (((a).f_type & MNT_LOCAL) == 0) + +/* always return true if queried for the properties of + the file system. If you think this is wrong under any + of the target platforms fix it!!!! */ +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* FREEBSD || NETBSD */ + +#if defined(LINUX) +# define __OSL_NFS_SUPER_MAGIC 0x6969 +# define __OSL_SMB_SUPER_MAGIC 0x517B +# define __OSL_MSDOS_SUPER_MAGIC 0x4d44 +# define __OSL_NTFS_SUPER_MAGIC 0x5346544e +# define __OSL_STATFS_STRUCT struct statfs +# define __OSL_STATFS(dir, sfs) statfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_bsize)) +# define __OSL_STATFS_IS_NFS(a) (__OSL_NFS_SUPER_MAGIC == (a).f_type) +# define __OSL_STATFS_IS_SMB(a) (__OSL_SMB_SUPER_MAGIC == (a).f_type) +# define __OSL_STATFS_ISREMOTE(a) (__OSL_STATFS_IS_NFS((a)) || __OSL_STATFS_IS_SMB((a))) +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) ((__OSL_MSDOS_SUPER_MAGIC != (a).f_type) && (__OSL_NTFS_SUPER_MAGIC != (a).f_type)) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) ((__OSL_MSDOS_SUPER_MAGIC != (a).f_type)) +#endif /* LINUX */ + +#if defined(SOLARIS) +# define __OSL_STATFS_STRUCT struct statvfs +# define __OSL_STATFS(dir, sfs) statvfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_frsize)) +# define __OSL_STATFS_TYPENAME(a) ((a).f_basetype) +# define __OSL_STATFS_ISREMOTE(a) (rtl_str_compare((a).f_basetype, "nfs") == 0) + +/* always return true if queried for the properties of + the file system. If you think this is wrong under any + of the target platforms fix it!!!! */ +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* SOLARIS */ + +# define __OSL_STATFS_INIT(a) (memset(&(a), 0, sizeof(__OSL_STATFS_STRUCT))) + +#else /* no statfs available */ + +# define __OSL_STATFS_STRUCT struct dummy {int i;} +# define __OSL_STATFS_INIT(a) ((void)0) +# define __OSL_STATFS(dir, sfs) (1) +# define __OSL_STATFS_ISREMOTE(sfs) (0) +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* HAVE_STATFS_H */ + + +static oslFileError osl_psz_getVolumeInformation ( + const sal_Char* pszDirectory, oslVolumeInfo* pInfo, sal_uInt32 uFieldMask) +{ + __OSL_STATFS_STRUCT sfs; + + if (!pInfo) + return osl_File_E_INVAL; + + __OSL_STATFS_INIT(sfs); + + pInfo->uValidFields = 0; + pInfo->uAttributes = 0; + + if ((__OSL_STATFS(pszDirectory, &sfs)) < 0) + { + oslFileError result = oslTranslateFileError(OSL_FET_ERROR, errno); + return (result); + } + + /* FIXME: how to detect the kind of storage (fixed, cdrom, ...) */ + if (uFieldMask & osl_VolumeInfo_Mask_Attributes) + { + if (__OSL_STATFS_ISREMOTE(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Remote; + + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + + if (uFieldMask & osl_VolumeInfo_Mask_FileSystemCaseHandling) + { + if (__OSL_STATFS_IS_CASE_SENSITIVE_FS(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Case_Sensitive; + + if (__OSL_STATFS_IS_CASE_PRESERVING_FS(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved; + + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + + pInfo->uTotalSpace = 0; + pInfo->uFreeSpace = 0; + pInfo->uUsedSpace = 0; + +#if defined(__OSL_STATFS_BLKSIZ) + + if ((uFieldMask & osl_VolumeInfo_Mask_TotalSpace) || + (uFieldMask & osl_VolumeInfo_Mask_UsedSpace)) + { + pInfo->uTotalSpace = __OSL_STATFS_BLKSIZ(sfs); + pInfo->uTotalSpace *= (sal_uInt64)(sfs.f_blocks); + pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace; + } + + if ((uFieldMask & osl_VolumeInfo_Mask_FreeSpace) || + (uFieldMask & osl_VolumeInfo_Mask_UsedSpace)) + { + pInfo->uFreeSpace = __OSL_STATFS_BLKSIZ(sfs); + + if (getuid() == 0) + pInfo->uFreeSpace *= (sal_uInt64)(sfs.f_bfree); + else + pInfo->uFreeSpace *= (sal_uInt64)(sfs.f_bavail); + + pInfo->uValidFields |= osl_VolumeInfo_Mask_FreeSpace; + } + +#endif /* __OSL_STATFS_BLKSIZ */ + + if ((pInfo->uValidFields & osl_VolumeInfo_Mask_TotalSpace) && + (pInfo->uValidFields & osl_VolumeInfo_Mask_FreeSpace )) + { + pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace; + pInfo->uValidFields |= osl_VolumeInfo_Mask_UsedSpace; + } + + pInfo->uMaxNameLength = 0; + if (uFieldMask & osl_VolumeInfo_Mask_MaxNameLength) + { + long nLen = pathconf(pszDirectory, _PC_NAME_MAX); + if (nLen > 0) + { + pInfo->uMaxNameLength = (sal_uInt32)nLen; + pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength; + } + } + + pInfo->uMaxPathLength = 0; + if (uFieldMask & osl_VolumeInfo_Mask_MaxPathLength) + { + long nLen = pathconf (pszDirectory, _PC_PATH_MAX); + if (nLen > 0) + { + pInfo->uMaxPathLength = (sal_uInt32)nLen; + pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength; + } + } + +#if defined(__OSL_STATFS_TYPENAME) + + if (uFieldMask & osl_VolumeInfo_Mask_FileSystemName) + { + rtl_string2UString( + &(pInfo->ustrFileSystemName), + __OSL_STATFS_TYPENAME(sfs), + rtl_str_getLength(__OSL_STATFS_TYPENAME(sfs)), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS); + OSL_ASSERT(pInfo->ustrFileSystemName != 0); + + pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName; + } + +#endif /* __OSL_STATFS_TYPENAME */ + + if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle) + { + /* FIXME: check also entries in mntent for the device + and fill it with correct values */ + + *pInfo->pDeviceHandle = osl_isFloppyDrive(pszDirectory); + + if (*pInfo->pDeviceHandle) + { + pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle; + pInfo->uAttributes |= osl_Volume_Attribute_Removeable; + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + } + return osl_File_E_None; +} + +/****************************************** + * 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; +} + + +/***************************************** + * osl_psz_removeFile + ****************************************/ +#if 0 +static oslFileError osl_psz_removeFile( const sal_Char* pszPath ) +{ + int nRet=0; + struct stat aStat; + + nRet = stat(pszPath,&aStat); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + if ( S_ISDIR(aStat.st_mode) ) + { + return osl_File_E_ISDIR; + } + + nRet = unlink(pszPath); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} +#endif + +/***************************************** + * osl_psz_createDirectory + ****************************************/ +#if 0 +static oslFileError osl_psz_createDirectory( const sal_Char* pszPath ) +{ + int nRet=0; + int mode = S_IRWXU | S_IRWXG | S_IRWXO; + + nRet = mkdir(pszPath,mode); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} +#endif +/***************************************** + * osl_psz_removeDirectory + ****************************************/ +#if 0 +static oslFileError osl_psz_removeDirectory( const sal_Char* pszPath ) +{ + int nRet=0; + + nRet = rmdir(pszPath); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} +#endif +/***************************************** + * oslDoMoveFile + ****************************************/ +#if 0 +static oslFileError oslDoMoveFile( const sal_Char* pszPath, const sal_Char* pszDestPath) +{ + oslFileError tErr=osl_File_E_invalidError; + + tErr = osl_psz_moveFile(pszPath,pszDestPath); + if ( tErr == osl_File_E_None ) + { + return tErr; + } + + if ( tErr != osl_File_E_XDEV ) + { + return tErr; + } + + tErr=osl_psz_copyFile(pszPath,pszDestPath); + + if ( tErr != osl_File_E_None ) + { + oslFileError tErrRemove; + tErrRemove=osl_psz_removeFile(pszDestPath); + return tErr; + } + + tErr=osl_psz_removeFile(pszPath); + + return tErr; +} +#endif +/***************************************** + * osl_psz_moveFile + ****************************************/ +#if 0 +static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath) +{ + + int nRet = 0; + + nRet = rename(pszPath,pszDestPath); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} +#endif +/***************************************** + * osl_psz_copyFile + ****************************************/ +#if 0 +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; +} +#endif + +/****************************************************************************** + * + * 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 ) +{ + oslFileError tErr = osl_File_E_NOSYS; + + tErr = osl_unmountFloppy(Handle); + + /* Perhaps current working directory is set to mount point */ + + if ( tErr ) + { + sal_Char *pszHomeDir = getenv("HOME"); + + if ( pszHomeDir && strlen( pszHomeDir ) && 0 == chdir( pszHomeDir ) ) + { + /* try again */ + + tErr = osl_unmountFloppy(Handle); + + OSL_ENSURE( tErr, "osl_unmountvolumeDevice: CWD was set to volume mount point" ); + } + } + + return tErr; +} + +/***************************************** + * osl_automountVolumeDevice + ****************************************/ + +oslFileError osl_automountVolumeDevice( oslVolumeDeviceHandle Handle ) +{ + oslFileError tErr = osl_File_E_NOSYS; + + tErr = osl_mountFloppy(Handle); + + return tErr; +} + +/***************************************** + * osl_getVolumeDeviceMountPath + ****************************************/ + +oslFileError osl_getVolumeDeviceMountPath( oslVolumeDeviceHandle Handle, rtl_uString **pstrPath ) +{ + oslVolumeDeviceHandleImpl* pItem = (oslVolumeDeviceHandleImpl*) Handle; + sal_Char Buffer[PATH_MAX]; + + Buffer[0] = '\0'; + + if ( pItem == 0 || pstrPath == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"Handle is:\n"); + osl_printFloppyHandle(pItem); +#endif + + snprintf(Buffer, sizeof(Buffer), "file://%s", pItem->pszMountPoint); + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"Mount Point is: '%s'\n",Buffer); +#endif + + oslMakeUStrFromPsz(Buffer, pstrPath); + + return osl_File_E_None; +} + +/***************************************** + * osl_acquireVolumeDeviceHandle + ****************************************/ + +oslFileError SAL_CALL osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle ) +{ + oslVolumeDeviceHandleImpl* pItem =(oslVolumeDeviceHandleImpl*) Handle; + + if ( pItem == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + + ++pItem->RefCount; + + return osl_File_E_None; +} + +/***************************************** + * osl_releaseVolumeDeviceHandle + ****************************************/ + +oslFileError osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle ) +{ + oslVolumeDeviceHandleImpl* pItem =(oslVolumeDeviceHandleImpl*) Handle; + + if ( pItem == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + + --pItem->RefCount; + + if ( pItem->RefCount == 0 ) + { + rtl_freeMemory(pItem); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_newVolumeDeviceHandleImpl + ****************************************/ + +static oslVolumeDeviceHandleImpl* osl_newVolumeDeviceHandleImpl() +{ + oslVolumeDeviceHandleImpl* pHandle; + const size_t nSizeOfHandle = sizeof(oslVolumeDeviceHandleImpl); + + pHandle = (oslVolumeDeviceHandleImpl*) rtl_allocateMemory (nSizeOfHandle); + if (pHandle != NULL) + { + pHandle->ident[0] = 'O'; + pHandle->ident[1] = 'V'; + pHandle->ident[2] = 'D'; + pHandle->ident[3] = 'H'; + pHandle->pszMountPoint[0] = '\0'; + pHandle->pszFilePath[0] = '\0'; + pHandle->pszDevice[0] = '\0'; + pHandle->RefCount = 1; + } + return pHandle; +} + +/***************************************** + * osl_freeVolumeDeviceHandleImpl + ****************************************/ + +static void osl_freeVolumeDeviceHandleImpl (oslVolumeDeviceHandleImpl* pHandle) +{ + if (pHandle != NULL) + rtl_freeMemory (pHandle); +} + + +/****************************************************************************** + * + * OS/2 FLOPPY FUNCTIONS + * + *****************************************************************************/ + +#if defined(OS2) +static oslVolumeDeviceHandle osl_isFloppyDrive(const sal_Char* pszPath) +{ + return NULL; +} + +static oslFileError osl_mountFloppy(oslVolumeDeviceHandle hFloppy) +{ + return osl_File_E_BUSY; +} + +static oslFileError osl_unmountFloppy(oslVolumeDeviceHandle hFloppy) +{ + return osl_File_E_BUSY; +} + +static sal_Bool osl_getFloppyMountEntry(const sal_Char* pszPath, oslVolumeDeviceHandleImpl* pItem) +{ + return sal_False; +} + +static sal_Bool osl_isFloppyMounted(oslVolumeDeviceHandleImpl* pDevice) +{ + return sal_False; +} + + +#ifdef DEBUG_OSL_FILE +static void osl_printFloppyHandle(oslVolumeDeviceHandleImpl* pItem) +{ + if (pItem == 0 ) + { + fprintf(stderr,"NULL Handle\n"); + return; + } + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Invalid Handle]\n"); +#endif + return; + } + + + fprintf(stderr,"MountPoint : '%s'\n",pItem->pszMountPoint); + fprintf(stderr,"FilePath : '%s'\n",pItem->pszFilePath); + fprintf(stderr,"Device : '%s'\n",pItem->pszDevice); + + return; +} +#endif + +#endif /* OS2 */ diff --git a/sal/osl/os2/file_error_transl.cxx b/sal/osl/os2/file_error_transl.cxx new file mode 100644 index 000000000000..fd296d9dd3d2 --- /dev/null +++ b/sal/osl/os2/file_error_transl.cxx @@ -0,0 +1,252 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _ERRNO_H + #include <errno.h> + #endif + + #ifndef _FILE_ERROR_TRANSL_H_ + #include "file_error_transl.h" + #endif + + #ifndef _OSL_DIAGNOSE_H_ + #include <osl/diagnose.h> + #endif + + +/******************************************** + * oslTranslateFileError + *******************************************/ + +oslFileError oslTranslateFileError(sal_Bool bIsError, int Errno) +{ + oslFileError osl_error = osl_File_E_invalidError; + + OSL_ENSURE((bIsError && (0 != Errno)) || (!bIsError && (0 == Errno)), "oslTranslateFileError strange input combination!"); + + /* Have a look at file_error_transl.h for + the reason that we do this here */ + if (bIsError && (0 == Errno)) + return osl_error; + + switch(Errno) + { + case 0: + osl_error = osl_File_E_None; + break; + + case EPERM: + osl_error = osl_File_E_PERM; + break; + + case ENOENT: + osl_error = osl_File_E_NOENT; + break; + + case ESRCH: + osl_error = osl_File_E_SRCH; + break; + + case EINTR: + osl_error = osl_File_E_INTR; + break; + + case EIO: + osl_error = osl_File_E_IO; + break; + + case ENXIO: + osl_error = osl_File_E_IO; + break; + + case E2BIG: + osl_error = osl_File_E_2BIG; + break; + + case ENOEXEC: + osl_error = osl_File_E_NOEXEC; + break; + + case EBADF: + osl_error = osl_File_E_BADF; + break; + + case ECHILD: + osl_error = osl_File_E_CHILD; + break; + + case EAGAIN: + osl_error = osl_File_E_AGAIN; + break; + + case ENOMEM: + osl_error = osl_File_E_NOMEM; + break; + + case EACCES: + osl_error = osl_File_E_ACCES; + break; + + case EFAULT: + osl_error = osl_File_E_FAULT; + break; + + case EBUSY: + osl_error = osl_File_E_BUSY; + break; + + case EEXIST: + osl_error = osl_File_E_EXIST; + break; + + case EXDEV: + osl_error = osl_File_E_XDEV; + break; + + case ENODEV: + osl_error = osl_File_E_NODEV; + break; + + case ENOTDIR: + osl_error = osl_File_E_NOTDIR; + break; + + case EISDIR: + osl_error = osl_File_E_ISDIR; + break; + + case EINVAL: + osl_error = osl_File_E_INVAL; + break; + + case ENFILE: + osl_error = osl_File_E_NFILE; + break; + + case EMFILE: + osl_error = osl_File_E_MFILE; + break; + + case ENOTTY: + osl_error = osl_File_E_NOTTY; + break; + + case EFBIG: + osl_error = osl_File_E_FBIG; + break; + + case ENOSPC: + osl_error = osl_File_E_NOSPC; + break; + + case ESPIPE: + osl_error = osl_File_E_SPIPE; + break; + + case EROFS: + osl_error = osl_File_E_ROFS; + break; + + case EMLINK: + osl_error = osl_File_E_MLINK; + break; + + case EPIPE: + osl_error = osl_File_E_PIPE; + break; + + case EDOM: + osl_error = osl_File_E_DOM; + break; + + case ERANGE: + osl_error = osl_File_E_RANGE; + break; + + case EDEADLK: + osl_error = osl_File_E_DEADLK; + break; + + case ENAMETOOLONG: + osl_error = osl_File_E_NAMETOOLONG; + break; + + case ENOLCK: + osl_error = osl_File_E_NOLCK; + break; + + case ENOSYS: + osl_error = osl_File_E_NOSYS; + break; + + case ENOTEMPTY: + osl_error = osl_File_E_NOTEMPTY; + break; + + case ELOOP: + osl_error = osl_File_E_LOOP; + break; + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) + case EILSEQ: + osl_error = osl_File_E_ILSEQ; + break; +#endif /* MACOSX */ + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD) || defined(OS2)) + case ENOLINK: + osl_error = osl_File_E_NOLINK; + break; +#endif /* MACOSX */ + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD) || defined(OS2)) + case EMULTIHOP: + osl_error = osl_File_E_MULTIHOP; + break; +#endif /* MACOSX */ + + case EUSERS: + osl_error = osl_File_E_USERS; + break; + + case EOVERFLOW: + osl_error = osl_File_E_OVERFLOW; + break; + + case ETIMEDOUT: + osl_error = osl_File_E_TIMEDOUT; + break; + + default: + /* FIXME translateFileError: is this alright? Or add a new one: osl_File_E_Unknown? */ + osl_error = osl_File_E_invalidError; + break; + } + + return osl_error; +} + diff --git a/sal/osl/os2/file_error_transl.h b/sal/osl/os2/file_error_transl.h new file mode 100644 index 000000000000..59d7b1d9faec --- /dev/null +++ b/sal/osl/os2/file_error_transl.h @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _FILE_ERROR_TRANSL_H_ +#define _FILE_ERROR_TRANSL_H_ + +#include <osl/file.h> +#include <sal/types.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************* + oslTranslateFileError + Translate errno's to osl file errors + + @param bIsError [in] specifies if nErrno + should be interpreted as error, + some libc functions signaling an error + but errno is nevertheless 0 in this + case the function should at least + return osl_File_E_Unknown but in no + case osl_File_E_None! + + @param nErrno [in] the errno if errno is 0 + and bIsError is true the function + returns osl_File_E_Unknown + + @returns the osl error code appropriate to + the errno + + *********************************************/ + +#define OSL_FET_SUCCESS sal_False +#define OSL_FET_ERROR sal_True + +oslFileError oslTranslateFileError(sal_Bool bIsError, int Errno); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sal/osl/os2/file_path_helper.cxx b/sal/osl/os2/file_path_helper.cxx new file mode 100644 index 000000000000..1aa5840deca4 --- /dev/null +++ b/sal/osl/os2/file_path_helper.cxx @@ -0,0 +1,377 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + /******************************************* + Includes + ******************************************/ + + #ifndef _OSL_THREAD_H_ + #include "osl/thread.h" + #endif + + #ifndef _OSL_FILE_PATH_HELPER_H_ + #include "file_path_helper.h" + #endif + + #ifndef _OSL_FILE_PATH_HELPER_HXX_ + #include "file_path_helper.hxx" + #endif + + #ifndef _OSL_UUNXAPI_HXX_ + #include "uunxapi.hxx" + #endif + + #ifndef _OSL_DIAGNOSE_H_ + #include <osl/diagnose.h> + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + /******************************************* + Constants + ******************************************/ + + const sal_Unicode FPH_CHAR_PATH_SEPARATOR = (sal_Unicode)'\\'; + const sal_Unicode FPH_CHAR_DOT = (sal_Unicode)'.'; + const sal_Unicode FPH_CHAR_COLON = (sal_Unicode)':'; + + inline const rtl::OUString FPH_PATH_SEPARATOR() + { return rtl::OUString::createFromAscii("\\"); } + inline const rtl::OUString FPH_LOCAL_DIR_ENTRY() + { return rtl::OUString::createFromAscii("."); } + inline const rtl::OUString FPH_PARENT_DIR_ENTRY() + { return rtl::OUString::createFromAscii(".."); } + + /******************************************* + * osl_systemPathRemoveSeparator + ******************************************/ + + void SAL_CALL osl_systemPathRemoveSeparator(rtl_uString* pustrPath) + { + OSL_PRECOND(pustrPath, "osl_systemPathRemoveSeparator: Invalid parameter"); + + // maybe there are more than one separator at end + // so we run in a loop + while ((pustrPath->length > 1) && (FPH_CHAR_PATH_SEPARATOR == pustrPath->buffer[pustrPath->length - 1])) + { + pustrPath->length--; + pustrPath->buffer[pustrPath->length] = (sal_Unicode)'\0'; + } + + OSL_POSTCOND((0 == pustrPath->length) || (1 == pustrPath->length) || \ + (pustrPath->length > 1 && pustrPath->buffer[pustrPath->length - 1] != FPH_CHAR_PATH_SEPARATOR), \ + "osl_systemPathRemoveSeparator: Post condition failed"); + } + + /******************************************* + osl_systemPathEnsureSeparator + ******************************************/ + + void SAL_CALL osl_systemPathEnsureSeparator(rtl_uString** ppustrPath) + { + OSL_PRECOND(ppustrPath && (NULL != *ppustrPath), \ + "osl_systemPathEnsureSeparator: Invalid parameter"); + + rtl::OUString path(*ppustrPath); + sal_Int32 lp = path.getLength(); + sal_Int32 i = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR); + + if ((lp > 1 && i != (lp - 1)) || ((lp < 2) && i < 0)) + { + path += FPH_PATH_SEPARATOR(); + rtl_uString_assign(ppustrPath, path.pData); + } + + OSL_POSTCOND(path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR) == (path.getLength() - 1), \ + "osl_systemPathEnsureSeparator: Post condition failed"); + } + + /******************************************* + * osl_systemPathIsRelativePath + ******************************************/ + + sal_Bool SAL_CALL osl_systemPathIsRelativePath(const rtl_uString* pustrPath) + { + OSL_PRECOND(pustrPath, "osl_systemPathIsRelativePath: Invalid parameter"); + return (!osl_systemPathIsAbsolutePath(pustrPath)); + } + + /****************************************** + * osl_systemPathIsAbsolutePath + *****************************************/ + + sal_Bool SAL_CALL osl_systemPathIsAbsolutePath(const rtl_uString* pustrPath) + { + OSL_PRECOND(pustrPath, "osl_systemPathIsAbsolutePath: Invalid parameter"); + if (pustrPath->length == 0) + return sal_False; + if (pustrPath->buffer[0] == FPH_CHAR_PATH_SEPARATOR) + return sal_True; + if (pustrPath->buffer[1] == FPH_CHAR_COLON + && pustrPath->buffer[2] == FPH_CHAR_PATH_SEPARATOR) + return sal_True; + return sal_False; + } + + /****************************************** + osl_systemPathMakeAbsolutePath + *****************************************/ + + void SAL_CALL osl_systemPathMakeAbsolutePath( + const rtl_uString* pustrBasePath, + const rtl_uString* pustrRelPath, + rtl_uString** ppustrAbsolutePath) +{ + rtl::OUString base(rtl_uString_getStr(const_cast<rtl_uString*>(pustrBasePath))); + rtl::OUString rel(const_cast<rtl_uString*>(pustrRelPath)); + + if (base.getLength() > 0) + osl_systemPathEnsureSeparator(&base.pData); + + base += rel; + + rtl_uString_acquire(base.pData); + *ppustrAbsolutePath = base.pData; +} + + + /***************************************** + osl_systemPathGetParent + ****************************************/ + + sal_Int32 SAL_CALL osl_systemPathGetParent(rtl_uString* pustrPath) + { + return 0; + } + + /******************************************* + osl_systemPathGetFileOrLastDirectoryPart + ******************************************/ + + void SAL_CALL osl_systemPathGetFileNameOrLastDirectoryPart( + const rtl_uString* pustrPath, + rtl_uString** ppustrFileNameOrLastDirPart) +{ + OSL_PRECOND(pustrPath && ppustrFileNameOrLastDirPart, \ + "osl_systemPathGetFileNameOrLastDirectoryPart: Invalid parameter"); + + rtl::OUString path(const_cast<rtl_uString*>(pustrPath)); + + osl_systemPathRemoveSeparator(path.pData); + + rtl::OUString last_part; + + if (path.getLength() > 1 || (1 == path.getLength() && *path.getStr() != FPH_CHAR_PATH_SEPARATOR)) + { + sal_Int32 idx_ps = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR); + idx_ps++; // always right to increment by one even if idx_ps == -1! + last_part = rtl::OUString(path.getStr() + idx_ps); + } + rtl_uString_assign(ppustrFileNameOrLastDirPart, last_part.pData); +} + + + /******************************************** + osl_systemPathIsHiddenFileOrDirectoryEntry + *********************************************/ + + sal_Bool SAL_CALL osl_systemPathIsHiddenFileOrDirectoryEntry( + const rtl_uString* pustrPath) +{ + OSL_PRECOND(pustrPath, "osl_systemPathIsHiddenFileOrDirectoryEntry: Invalid parameter"); + + sal_Bool is_hidden = sal_False; + + if (pustrPath->length > 0) + { + rtl::OUString fdp; + + osl_systemPathGetFileNameOrLastDirectoryPart(pustrPath, &fdp.pData); + + is_hidden = ((fdp.pData->length > 0) && (fdp.pData->buffer[0] == FPH_CHAR_DOT) && + !osl_systemPathIsLocalOrParentDirectoryEntry(fdp.pData)); + } + + return is_hidden; +} + + + /************************************************ + osl_systemPathIsLocalOrParentDirectoryEntry + ************************************************/ + +sal_Bool SAL_CALL osl_systemPathIsLocalOrParentDirectoryEntry( + const rtl_uString* pustrPath) +{ + OSL_PRECOND(pustrPath, "osl_systemPathIsLocalOrParentDirectoryEntry: Invalid parameter"); + + rtl::OUString dirent; + + osl_systemPathGetFileNameOrLastDirectoryPart(pustrPath, &dirent.pData); + + return ( + (dirent == FPH_LOCAL_DIR_ENTRY()) || + (dirent == FPH_PARENT_DIR_ENTRY()) + ); +} + +/*********************************************** + Simple iterator for a path list separated by + the specified character + **********************************************/ + +class path_list_iterator +{ +public: + + /****************************************** + constructor + + after construction get_current_item + returns the first path in list, no need + to call reset first + *****************************************/ + path_list_iterator(const rtl::OUString& path_list, sal_Unicode list_separator = FPH_CHAR_COLON) : + m_path_list(path_list), + m_end(m_path_list.getStr() + m_path_list.getLength() + 1), + m_separator(list_separator) + { + reset(); + } + + /****************************************** + reset the iterator + *****************************************/ + void reset() + { + m_path_segment_begin = m_path_segment_end = m_path_list.getStr(); + advance(); + } + + /****************************************** + move the iterator to the next position + *****************************************/ + void next() + { + OSL_PRECOND(!done(), "path_list_iterator: Already done!"); + + m_path_segment_begin = ++m_path_segment_end; + advance(); + } + + /****************************************** + check if done + *****************************************/ + bool done() const + { + return (m_path_segment_end >= m_end); + } + + /****************************************** + return the current item + *****************************************/ + rtl::OUString get_current_item() const + { + return rtl::OUString( + m_path_segment_begin, + (m_path_segment_end - m_path_segment_begin)); + } + +private: + + /****************************************** + move m_path_end to the next separator or + to the edn of the string + *****************************************/ + void advance() + { + while (!done() && *m_path_segment_end && (*m_path_segment_end != m_separator)) + ++m_path_segment_end; + + OSL_ASSERT(m_path_segment_end <= m_end); + } + +private: + rtl::OUString m_path_list; + const sal_Unicode* m_end; + const sal_Unicode m_separator; + const sal_Unicode* m_path_segment_begin; + const sal_Unicode* m_path_segment_end; + +// prevent copy and assignment +private: + /****************************************** + copy constructor + remember: do not simply copy m_path_begin + and m_path_end because they point to + the memory of other.m_path_list! + *****************************************/ + path_list_iterator(const path_list_iterator& other); + + /****************************************** + assignment operator + remember: do not simply copy m_path_begin + and m_path_end because they point to + the memory of other.m_path_list! + *****************************************/ + path_list_iterator& operator=(const path_list_iterator& other); +}; + + /************************************************ + osl_searchPath + ***********************************************/ + +sal_Bool SAL_CALL osl_searchPath( + const rtl_uString* pustrFilePath, + const rtl_uString* pustrSearchPathList, + rtl_uString** ppustrPathFound) +{ + OSL_PRECOND(pustrFilePath && pustrSearchPathList && ppustrPathFound, "osl_searchPath: Invalid parameter"); + + bool bfound = false; + rtl::OUString fp(const_cast<rtl_uString*>(pustrFilePath)); + rtl::OUString pl = rtl::OUString(const_cast<rtl_uString*>(pustrSearchPathList)); + path_list_iterator pli(pl); + + while (!pli.done()) + { + rtl::OUString p = pli.get_current_item(); + osl::systemPathEnsureSeparator(p); + p += fp; + + if (osl::access(p, F_OK) > -1) + { + bfound = true; + rtl_uString_assign(ppustrPathFound, p.pData); + break; + } + pli.next(); + } + return bfound; +} diff --git a/sal/osl/os2/file_path_helper.h b/sal/osl/os2/file_path_helper.h new file mode 100644 index 000000000000..88b8ccbe9b6a --- /dev/null +++ b/sal/osl/os2/file_path_helper.h @@ -0,0 +1,292 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_FILE_PATH_HELPER_H_ + #define _OSL_FILE_PATH_HELPER_H_ + + + #ifndef _SAL_TYPES_H_ + #include <sal/types.h> + #endif + + #ifndef _RTL_USTRING_H_ + #include <rtl/ustring.h> + #endif + + + #ifdef __cplusplus + extern "C" + { + #endif + + + /******************************************* + osl_systemPathRemoveSeparator + Removes the last separator from the + given system path if any and if the path + is not the root path '/' + + @param ppustrPath [inout] a system path + if the path is not the root path + and the last character is a + path separator it will be cut off + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + void SAL_CALL osl_systemPathRemoveSeparator( + /*inout*/ rtl_uString* pustrPath); + + /******************************************* + osl_systemPathEnsureSeparator + Adds a trailing path separator to the + given system path if not already there + and if the path is not the root path '/' + + @param pustrPath [inout] a system path + if the path is not the root path + '/' and has no trailing separator + a separator will be added + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + void SAL_CALL osl_systemPathEnsureSeparator( + /*inout*/ rtl_uString** ppustrPath); + + /******************************************* + osl_systemPathIsRelativePath + Returns true if the given path is a + relative path and so starts not with '/' + + @param pustrPath [in] a system path + pustrPath must not be NULL + + @returns sal_True if the given path + doesn't start with a separator + else sal_False will be returned + + ******************************************/ + + sal_Bool SAL_CALL osl_systemPathIsRelativePath( + const rtl_uString* pustrPath); + + /****************************************** + osl_systemPathIsAbsolutePath + Returns true if the given path is an + absolute path and so starts with a '/' + + @param pustrPath [in] a system path + pustrPath must not be NULL + + @returns sal_True if the given path + start's with a separator else + sal_False will be returned + + *****************************************/ + + sal_Bool SAL_CALL osl_systemPathIsAbsolutePath( + const rtl_uString* pustrPath); + + /****************************************** + osl_systemPathMakeAbsolutePath + Append a relative path to a base path + + @param pustrBasePath [in] a system + path that will be considered as + base path + pustrBasePath must not be NULL + + @param pustrRelPath [in] a system path + that will be considered as + relative path + pustrBasePath must not be NULL + + @param ppustrAbsolutePath [out] the + resulting path which is a + concatination of the base and + the relative path + if base path is empty the + resulting absolute path is the + relative path + if relative path is empty the + resulting absolute path is the + base path + if base and relative path are + empty the resulting absolute + path is also empty + ppustrAbsolutePath must not be + NULL and *ppustrAbsolutePath + must be 0 or point to a valid + rtl_uString + + *****************************************/ + + void SAL_CALL osl_systemPathMakeAbsolutePath( + const rtl_uString* pustrBasePath, + const rtl_uString* pustrRelPath, + rtl_uString** ppustrAbsolutePath); + + /***************************************** + osl_systemPathGetParent + Replaces the last occurrance of a path + separator with '\0' and returns the + position where the '/' was replaced + + @param pustrPath [inout] a system + path, the last separator of + this path will be replaced by + a '\0' + if the path is the root path + '/' or the path is considered + as to have no parent, e.g. + '/NoParent' or 'NoParent' or + the path is empty no + replacement will be made + pustrPath must not be NULL + + @returns the position of the last path + separator that was replaced + or 0 if no replacement took + place + + ****************************************/ + + sal_Int32 SAL_CALL osl_systemPathGetParent( + /*inout*/ rtl_uString* pustrPath); + + /***************************************** + osl_systemPathGetFileOrLastDirectoryPart + Returns the file or the directory part + of the given path + + @param pustrPath [in] a system path, + must not be NULL + + @param ppustrFileOrDirPart [out] on + return receives the last part + of the given directory or the + file name + if pustrPath is the root path + '/' an empty string will be + returned + if pustrPath has a trailing + '/' the last part before the + '/' will be returned else + the part after the last '/' + will be returned + + @returns nothing + + ****************************************/ + void SAL_CALL osl_systemPathGetFileNameOrLastDirectoryPart( + const rtl_uString* pustrPath, + rtl_uString** ppustrFileNameOrLastDirPart); + + + /******************************************** + osl_systemPathIsHiddenFileOrDirectoryEntry + Returns sal_True if the last part of + given system path is not '.' or '..' + alone and starts with a '.' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of + the given system path starts + with '.' or sal_False the last + part is '.' or '..' alone or + doesn't start with a dot + + *********************************************/ + + sal_Bool SAL_CALL osl_systemPathIsHiddenFileOrDirectoryEntry( + const rtl_uString* pustrPath); + + + /************************************************ + osl_systemPathIsLocalOrParentDirectoryEntry + Returns sal_True if the last part of the given + system path is the local directory entry '.' + or the parent directory entry '..' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of the + given system path is '.' or '..' + else sal_False + + ************************************************/ + + sal_Bool SAL_CALL osl_systemPathIsLocalOrParentDirectoryEntry( + const rtl_uString* pustrPath); + + + /************************************************ + osl_searchPath + Searches for a file name or path name in all + directories specified by a given path list. + Symbolic links in the resulting path will not be + resolved, it's up to the caller to do this. + + @param pustrFilePath [in] a file name or + directory name to search for, the name must + be provided as system path not as a file URL + + @param pustrSearchPathList [in] a ':' + separated list of paths in which to search for + the file or directory name + + @ppustrPathFound [out] on success receives the + complete path of the file or directory found + as a system path + + @returns sal_True if the specified file or + directory was found else sal_False + ***********************************************/ + + sal_Bool SAL_CALL osl_searchPath( + const rtl_uString* pustrFilePath, + const rtl_uString* pustrSearchPathList, + rtl_uString** ppustrPathFound); + + + #ifdef __cplusplus + } + #endif + + + #endif /* #ifndef _OSL_PATH_HELPER_H_ */ + diff --git a/sal/osl/os2/file_path_helper.hxx b/sal/osl/os2/file_path_helper.hxx new file mode 100644 index 000000000000..5310f462efc0 --- /dev/null +++ b/sal/osl/os2/file_path_helper.hxx @@ -0,0 +1,296 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_FILE_PATH_HELPER_HXX_ +#define _OSL_FILE_PATH_HELPER_HXX_ + + +#ifndef _OSL_FILE_PATH_HELPER_H_ +#include "file_path_helper.h" +#endif + +#include <rtl/ustring.hxx> + + +namespace osl +{ + + /******************************************* + systemPathRemoveSeparator + Removes the last separator from the + given system path if any and if the path + is not the root path '/' + + @param ppustrPath [inout] a system path + if the path is not the root path + and the last character is a + path separator it will be cut off + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + inline void systemPathRemoveSeparator(/*inout*/ rtl::OUString& Path) + { + osl_systemPathRemoveSeparator(Path.pData); + } + + /******************************************* + systemPathEnsureSeparator + Adds a trailing path separator to the + given system path if not already there + and if the path is not the root path '/' + + @param pustrPath [inout] a system path + if the path is not the root path + '/' and has no trailing separator + a separator will be added + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + inline void systemPathEnsureSeparator(/*inout*/ rtl::OUString& Path) + { + osl_systemPathEnsureSeparator(&Path.pData); + } + + /******************************************* + systemPathIsRelativePath + Returns true if the given path is a + relative path and so starts not with '/' + + @param pustrPath [in] a system path + pustrPath must not be NULL + + @returns sal_True if the given path + doesn't start with a separator + else sal_False will be returned + + ******************************************/ + + inline bool systemPathIsRelativePath(const rtl::OUString& Path) + { + return osl_systemPathIsRelativePath(Path.pData); + } + + /****************************************** + systemPathIsAbsolutePath + Returns true if the given path is an + absolute path and so starts with a '/' + + @param pustrPath [in] a system path + pustrPath must not be NULL + + @returns sal_True if the given path + start's with a separator else + sal_False will be returned + + *****************************************/ + + inline bool systemPathIsAbsolutePath(const rtl::OUString& Path) + { + return osl_systemPathIsAbsolutePath(Path.pData); + } + + /****************************************** + systemPathMakeAbsolutePath + Append a relative path to a base path + + @param pustrBasePath [in] a system + path that will be considered as + base path + pustrBasePath must not be NULL + + @param pustrRelPath [in] a system path + that will be considered as + relative path + pustrBasePath must not be NULL + + @param ppustrAbsolutePath [out] the + resulting path which is a + concatination of the base and + the relative path + if base path is empty the + resulting absolute path is the + relative path + if relative path is empty the + resulting absolute path is the + base path + if base and relative path are + empty the resulting absolute + path is also empty + ppustrAbsolutePath must not be + NULL and *ppustrAbsolutePath + must be 0 or point to a valid + rtl_uString + + *****************************************/ + + inline void systemPathMakeAbsolutePath( + const rtl::OUString& BasePath, + const rtl::OUString& RelPath, + rtl::OUString& AbsolutePath) + { + osl_systemPathMakeAbsolutePath( + BasePath.pData, RelPath.pData, &AbsolutePath.pData); + } + + /***************************************** + systemPathGetParent + Replaces the last occurrance of a path + separator with '\0' and returns the + position where the '/' was replaced + + @param pustrPath [inout] a system + path, the last separator of + this path will be replaced by + a '\0' + if the path is the root path + '/' or the path is considered + as to have no parent, e.g. + '/NoParent' or 'NoParent' or + the path is empty no + replacement will be made + pustrPath must not be NULL + + @returns the position of the last path + separator that was replaced + or 0 if no replacement took + place + + ****************************************/ + + inline sal_Int32 systemPathGetParent(/*inout*/ rtl::OUString& Path) + { + return osl_systemPathGetParent(Path.pData); + } + + /***************************************** + systemPathGetFileOrLastDirectoryPart + Returns the file or the directory part + of the given path + + @param pustrPath [in] a system path, + must not be NULL + + @param ppustrFileOrDirPart [out] on + return receives the last part + of the given directory or the + file name + if pustrPath is the root path + '/' an empty string will be + returned + if pustrPath has a trailing + '/' the last part before the + '/' will be returned else + the part after the last '/' + will be returned + + @returns nothing + + ****************************************/ + + inline void systemPathGetFileNameOrLastDirectoryPart( + const rtl::OUString& Path, + rtl::OUString& FileNameOrLastDirPart) + { + osl_systemPathGetFileNameOrLastDirectoryPart( + Path.pData, &FileNameOrLastDirPart.pData); + } + + + /******************************************** + systemPathIsHiddenFileOrDirectoryEntry + Returns sal_True if the last part of + given system path is not '.' or '..' + alone and starts with a '.' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of + the given system path starts + with '.' or sal_False the last + part is '.' or '..' alone or + doesn't start with a dot + + *********************************************/ + + inline bool systemPathIsHiddenFileOrDirectoryEntry( + const rtl::OUString& Path) + { + return osl_systemPathIsHiddenFileOrDirectoryEntry(Path.pData); + } + + + /************************************************ + systemPathIsLocalOrParentDirectoryEntry + Returns sal_True if the last part of the given + system path is the local directory entry '.' + or the parent directory entry '..' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of the + given system path is '.' or '..' + else sal_False + + ************************************************/ + + inline bool systemPathIsLocalOrParentDirectoryEntry( + const rtl::OUString& Path) + { + return osl_systemPathIsLocalOrParentDirectoryEntry(Path.pData); + } + + /************************************************ + searchPath + ***********************************************/ + + inline bool searchPath( + const rtl::OUString& ustrFilePath, + const rtl::OUString& ustrSearchPathList, + rtl::OUString& ustrPathFound) + { + return osl_searchPath( + ustrFilePath.pData, + ustrSearchPathList.pData, + &ustrPathFound.pData); + } + + + } // namespace osl + + + #endif /* #ifndef _OSL_PATH_HELPER_HXX_ */ + diff --git a/sal/osl/os2/file_url.cxx b/sal/osl/os2/file_url.cxx new file mode 100644 index 000000000000..e3b5fbf00c48 --- /dev/null +++ b/sal/osl/os2/file_url.cxx @@ -0,0 +1,1626 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <ctype.h> +#include "system.h" + +#ifndef _LIMITS_H +#include <limits.h> +#endif + +#ifndef _ERRNO_H +#include <errno.h> +#endif + +#ifndef _STDLIB_H_ +#include <stdlib.h> +#endif + +#ifndef _STRINGS_H +#include <strings.h> +#endif + +#ifndef _UNISTD_H +#include <unistd.h> +#endif +#include <osl/file.h> +#include <osl/security.h> +#include <rtl/uri.h> +#include <osl/diagnose.h> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.h> + +#ifndef _OSL_TREAD_H_ +#include <osl/thread.h> +#endif +#include <osl/file.hxx> +#include <osl/mutex.h> +#include <osl/process.h> +#include "file_error_transl.h" + +#ifndef _FILE_URL_H_ +#include "file_url.h" +#endif +#include "file_path_helper.hxx" + +#ifndef _OSL_UUNXAPI_HXX_ +#include "uunxapi.hxx" +#endif + +#include <wchar.h> +#include <wctype.h> + +/*************************************************** + + General note + + This file contains the part that handles File URLs. + + File URLs as scheme specific notion of URIs + (RFC2396) may be handled platform independend, but + will not in osl which is considered wrong. + Future version of osl should handle File URLs this + way. In rtl/uri there is already an URI parser etc. + so this code should be consolidated. + + **************************************************/ + +oslMutex g_CurrentDirectoryMutex; + + +/*************************************************** + * forward + **************************************************/ + +void _osl_warnFile(const char*, rtl_uString*); +rtl_uString* oslMakeUStrFromPsz(const sal_Char* pszStr,rtl_uString** uStr); + +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); + +/*************************************************** + * namespace directives + **************************************************/ + +using namespace osl; + +/****************************************************************************** + * + * Exported Module Functions + * + *****************************************************************************/ + +/* a slightly modified version of Pchar in rtl/source/uri.c */ +const sal_Bool uriCharClass[128] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /* pqrstuvwxyz{|}~ */ +}; + + +/* check for top wrong usage strings */ +/* +static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len ) +{ + rtl_uString *pTmp = NULL; + sal_Bool bRet; + + rtl_uString_newFromStr_WithLength( &pTmp, path, len ); + + rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length ); + + bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) ); + + rtl_uString_release( pTmp ); + return bRet; +} +*/ + + +/****************************************************************************/ +/* osl_getFileURLFromSystemPath */ +/****************************************************************************/ + +BOOL WINAPI IsValidFilePathComponent( + LPCTSTR lpComponent, LPCTSTR *lppComponentEnd, DWORD dwFlags) +{ + LPCTSTR lpComponentEnd = NULL; + LPCTSTR lpCurrent = lpComponent; + BOOL fValid = TRUE; /* Assume success */ + TCHAR cLast = 0; + + /* Path component length must not exceed MAX_PATH */ + + while ( !lpComponentEnd && lpCurrent && lpCurrent - lpComponent < _MAX_PATH ) + { + switch ( *lpCurrent ) + { + /* Both backslash and slash determine the end of a path component */ + case '\0': + case '/': + case '\\': + switch ( cLast ) + { + /* Component must not end with '.' or blank and can't be empty */ + + case '.': + if ( dwFlags & VALIDATEPATH_ALLOW_ELLIPSE ) + { + if ( 1 == lpCurrent - lpComponent ) + { + /* Current directory is O.K. */ + lpComponentEnd = lpCurrent; + break; + } + else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent ) + { + /* Parent directory is O.K. */ + lpComponentEnd = lpCurrent; + break; + } + } + case 0: + case ' ': + lpComponentEnd = lpCurrent - 1; + fValid = FALSE; + break; + default: + lpComponentEnd = lpCurrent; + break; + } + break; + /* '?' and '*' are valid wildcards but not valid file name characters */ + case '?': + case '*': + if ( dwFlags & VALIDATEPATH_ALLOW_WILDCARDS ) + break; + /* The following characters are reserved */ + case '<': + case '>': + case '\"': + case '|': + case ':': + lpComponentEnd = lpCurrent; + fValid = FALSE; + break; + default: + /* Characters below ASCII 32 are not allowed */ + if ( *lpCurrent < ' ' ) + { + lpComponentEnd = lpCurrent; + fValid = FALSE; + } + break; + } + cLast = *lpCurrent++; + } + + /* If we don't reached the end of the component the length of the component was to long + ( See condition of while loop ) */ + if ( !lpComponentEnd ) + { + fValid = FALSE; + lpComponentEnd = lpCurrent; + } + + /* Test wether the component specifies a device name what is not allowed */ + + // MT: PERFORMANCE: + // This is very expensive. A lot of calls to _tcsicmp. + // in SRC6870m71 67.000 calls of this method while empty office start result into more than 1.500.00 calls of _tcsicmp! + // Possible optimizations + // - Array should be const static + // - Sorted array, use binary search + // - More intelligent check for com1-9, lpt1-9 + // Maybe make szComponent upper case, don't search case intensitive + // Talked to HRO: Could be removed. Shouldn't be used in OOo, and if used for something like a filename, it will lead to an error anyway. + /* + if ( fValid ) + { + LPCTSTR alpDeviceNames[] = + { + TEXT("CON"), + TEXT("PRN"), + TEXT("AUX"), + TEXT("CLOCK$"), + TEXT("NUL"), + TEXT("LPT1"), + TEXT("LPT2"), + TEXT("LPT3"), + TEXT("LPT4"), + TEXT("LPT5"), + TEXT("LPT6"), + TEXT("LPT7"), + TEXT("LPT8"), + TEXT("LPT9"), + TEXT("COM1"), + TEXT("COM2"), + TEXT("COM3"), + TEXT("COM4"), + TEXT("COM5"), + TEXT("COM6"), + TEXT("COM7"), + TEXT("COM8"), + TEXT("COM9") + }; + + TCHAR szComponent[MAX_PATH]; + int nComponentLength; + LPCTSTR lpDot; + int i; + + // A device name with an extension is also invalid + lpDot = _tcschr( lpComponent, '.' ); + + if ( !lpDot || lpDot > lpComponentEnd ) + nComponentLength = lpComponentEnd - lpComponent; + else + nComponentLength = lpDot - lpComponent; + + _tcsncpy( szComponent, lpComponent, nComponentLength ); + szComponent[nComponentLength] = 0; + + for ( i = 0; i < sizeof( alpDeviceNames ) / sizeof(LPCTSTR); i++ ) + { + if ( 0 == _tcsicmp( szComponent, alpDeviceNames[i] ) ) + { + lpComponentEnd = lpComponent; + fValid = FALSE; + break; + } + } + } + */ + + if ( fValid ) + { + // Empty components are not allowed + if ( lpComponentEnd - lpComponent < 1 ) + fValid = FALSE; + + // If we reached the end of the string NULL is returned + else if ( !*lpComponentEnd ) + lpComponentEnd = NULL; + + } + + if ( lppComponentEnd ) + *lppComponentEnd = lpComponentEnd; + + return fValid; +} + +//##################################################### +DWORD WINAPI IsValidFilePath(LPCTSTR lpszPath, LPCTSTR *lppError, DWORD dwFlags) +{ + LPCTSTR lpComponent; + BOOL fValid = TRUE; + DWORD dwPathType = PATHTYPE_ERROR; + + if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE ) + dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE; + + if ( !lpszPath ) + { + fValid = FALSE; + lpComponent = lpszPath; + } + + /* Test for UNC path notation */ + if ( 2 == _tcsspn( lpszPath, CHARSET_SEPARATOR ) ) + { + /* Place the pointer behind the leading to backslashes */ + + lpComponent = lpszPath + 2; + + fValid = IsValidFilePathComponent( lpComponent, &lpComponent, VALIDATEPATH_ALLOW_ELLIPSE ); + + /* So far we have a valid servername. Now let's see if we also have a network resource */ + + dwPathType = PATHTYPE_ABSOLUTE_UNC; + + if ( fValid ) + { + if ( lpComponent && !*++lpComponent ) + lpComponent = NULL; + + if ( !lpComponent ) + { +#if 0 + /* We only have a Server specification what is invalid */ + + lpComponent = lpszPath; + fValid = FALSE; +#else + dwPathType |= PATHTYPE_IS_SERVER; +#endif + } + else + { + /* Now test the network resource */ + + fValid = IsValidFilePathComponent( lpComponent, &lpComponent, 0 ); + + /* If we now reached the end of the path, everything is O.K. */ + + + if ( fValid && (!lpComponent || lpComponent && !*++lpComponent ) ) + { + lpComponent = NULL; + dwPathType |= PATHTYPE_IS_VOLUME; + } + } + } + } + + /* Local path verification. Must start with <drive>: */ + else if ( _istalpha( lpszPath[0] ) && ':' == lpszPath[1] ) + { + /* Place pointer behind correct drive specification */ + + lpComponent = lpszPath + 2; + + if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) ) + lpComponent++; + else if ( *lpComponent ) + fValid = FALSE; + + dwPathType = PATHTYPE_ABSOLUTE_LOCAL; + + /* Now we are behind the backslash or it was a simple drive without backslash */ + + if ( fValid && !*lpComponent ) + { + lpComponent = NULL; + dwPathType |= PATHTYPE_IS_VOLUME; + } + } + + /* Can be a relative path */ + else if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE ) + { + lpComponent = lpszPath; + + /* Relative path can start with a backslash */ + + if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) ) + { + lpComponent++; + if ( !*lpComponent ) + lpComponent = NULL; + } + + dwPathType = PATHTYPE_RELATIVE; + } + + /* Anything else is an error */ + else + { + fValid = FALSE; + lpComponent = lpszPath; + } + + /* Now validate each component of the path */ + while ( fValid && lpComponent ) + { + fValid = IsValidFilePathComponent( lpComponent, &lpComponent, dwFlags ); + + if ( fValid && lpComponent ) + { + lpComponent++; + + /* If the string behind the backslash is empty, we've done */ + + if ( !*lpComponent ) + lpComponent = NULL; + } + } + + if ( fValid && _tcslen( lpszPath ) >= _MAX_PATH ) + { + fValid = FALSE; + lpComponent = lpszPath + _MAX_PATH; + } + + if ( lppError ) + *lppError = lpComponent; + + return fValid ? dwPathType : PATHTYPE_ERROR; +} + +sal_Bool _osl_decodeURL( rtl_String* strUTF8, rtl_uString** pstrDecodedURL ) +{ + sal_Char *pBuffer; + const sal_Char *pSrcEnd; + const sal_Char *pSrc; + sal_Char *pDest; + sal_Int32 nSrcLen; + sal_Bool bValidEncoded = sal_True; /* Assume success */ + + /* The resulting decoded string length is shorter or equal to the source length */ + + nSrcLen = rtl_string_getLength(strUTF8); + pBuffer = reinterpret_cast<sal_Char*>(rtl_allocateMemory(nSrcLen + 1)); + + pDest = pBuffer; + pSrc = rtl_string_getStr(strUTF8); + pSrcEnd = pSrc + nSrcLen; + + /* Now decode the URL what should result in an UTF8 string */ + while ( bValidEncoded && pSrc < pSrcEnd ) + { + switch ( *pSrc ) + { + case '%': + { + sal_Char aToken[3]; + sal_Char aChar; + + pSrc++; + aToken[0] = *pSrc++; + aToken[1] = *pSrc++; + aToken[2] = 0; + + aChar = (sal_Char)strtoul( aToken, NULL, 16 ); + + /* The chars are path delimiters and must not be encoded */ + + if ( 0 == aChar || '\\' == aChar || '/' == aChar || ':' == aChar ) + bValidEncoded = sal_False; + else + *pDest++ = aChar; + } + break; + default: + *pDest++ = *pSrc++; + break; + } + } + + *pDest++ = 0; + + if ( bValidEncoded ) { + rtl_string2UString( pstrDecodedURL, pBuffer, rtl_str_getLength(pBuffer), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pstrDecodedURL != 0); + } + + rtl_freeMemory( pBuffer ); + + return bValidEncoded; +} + +//############################################# +void _osl_encodeURL( rtl_uString *strURL, rtl_String **pstrEncodedURL ) +{ + /* Encode non ascii characters within the URL */ + + rtl_String *strUTF8 = NULL; + sal_Char *pszEncodedURL; + const sal_Char *pURLScan; + sal_Char *pURLDest; + sal_Int32 nURLScanLen; + sal_Int32 nURLScanCount; + + rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); + + pszEncodedURL = (sal_Char*) rtl_allocateMemory( (rtl_string_getLength( strUTF8 ) * 3 + 1) * sizeof(sal_Char) ); + + pURLDest = pszEncodedURL; + pURLScan = rtl_string_getStr( strUTF8 ); + nURLScanLen = rtl_string_getLength( strUTF8 ); + nURLScanCount = 0; + + while ( nURLScanCount < nURLScanLen ) + { + sal_Char cCurrent = *pURLScan; + + switch ( cCurrent ) + { + default: + if (!( ( cCurrent >= 'a' && cCurrent <= 'z' ) || ( cCurrent >= 'A' && cCurrent <= 'Z' ) || ( cCurrent >= '0' && cCurrent <= '9' ) ) ) + { + sprintf( pURLDest, "%%%02X", (unsigned char)cCurrent ); + pURLDest += 3; + break; + } + case '!': + case '\'': + case '(': + case ')': + case '*': + case '-': + case '.': + case '_': + case '~': + case '$': + case '&': + case '+': + case ',': + case '=': + case '@': + case ':': + case '/': + case '\\': + case '|': + *pURLDest++ = cCurrent; + break; + case 0: + break; + } + + pURLScan++; + nURLScanCount++; + } + + + *pURLDest = 0; + + rtl_string_release( strUTF8 ); + rtl_string_newFromStr( pstrEncodedURL, pszEncodedURL ); + rtl_freeMemory( pszEncodedURL ); +} + +//############################################# +oslFileError SAL_CALL _osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** pstrURL ) +{ + oslFileError nError = osl_File_E_INVAL; /* Assume failure */ + rtl_uString *strTempURL = NULL; + DWORD dwPathType = PATHTYPE_ERROR; + + if (strPath) + dwPathType = IsValidFilePath(strPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE); + + if (dwPathType) + { + rtl_uString *strTempPath = NULL; + + /* Replace backslashes */ + + rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' ); + + switch ( dwPathType & PATHTYPE_MASK_TYPE ) + { + case PATHTYPE_RELATIVE: + rtl_uString_assign( &strTempURL, strTempPath ); + nError = osl_File_E_None; + break; + case PATHTYPE_ABSOLUTE_UNC: + rtl_uString_newFromAscii( &strTempURL, "file:" ); + rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath ); + nError = osl_File_E_None; + break; + case PATHTYPE_ABSOLUTE_LOCAL: + rtl_uString_newFromAscii( &strTempURL, "file:///" ); + rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath ); + nError = osl_File_E_None; + break; + default: + break; + } + + /* Release temp path */ + + rtl_uString_release( strTempPath ); + } + + if ( osl_File_E_None == nError ) + { + rtl_String *strEncodedURL = NULL; + + /* Encode the URL */ + + _osl_encodeURL( strTempURL, &strEncodedURL ); + + /* Provide URL via unicode string */ + + rtl_string2UString( pstrURL, rtl_string_getStr(strEncodedURL), rtl_string_getLength(strEncodedURL), RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pstrURL != 0); + rtl_string_release( strEncodedURL ); + } + + /* Release temp URL */ + + if ( strTempURL ) + rtl_uString_release( strTempURL ); + + /* + OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath ); + */ + + return nError; +} + +oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL ) +{ + return _osl_getFileURLFromSystemPath( ustrSystemPath, pustrFileURL ); +#if 0 + static const sal_Unicode pDoubleSlash[2] = { '/', '/' }; + + rtl_uString *pTmp = NULL; + sal_Int32 nIndex; + + if( 0 == ustrSystemPath->length ) + return osl_File_E_INVAL; + + /* YD convert '\' to '/' */ + rtl_ustr_replaceChar( ustrSystemPath->buffer, '\\', '/' ); + + /* temporary hack: if already file url, return ustrSystemPath */ + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) ) + { + /* + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) ) + { + OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" ); + rtl_uString_assign( pustrFileURL, ustrSystemPath ); + } + else + { + rtl_uString *pTmp2 = NULL; + + OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" ); + rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 ); + rtl_uString_newFromAscii( &pTmp2, "file://" ); + rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 ); + rtl_uString_release( pTmp2 ); + } + return osl_File_E_None; + */ + return osl_File_E_INVAL; + } + + + /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ + if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] ) + { + /* check if another user is specified */ + if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) ) + { + /* osl_getHomeDir returns file URL */ + osl_getHomeDir( osl_getCurrentSecurity(), &pTmp ); + + /* remove "file://" prefix */ + rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 ); + + /* replace '~' in original string */ + rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp ); + } + + else + { + /* FIXME: replace ~user with users home directory */ + return osl_File_E_INVAL; + } + } + + /* check if initial string contains double instances of '/' */ + nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 ); + if( -1 != nIndex ) + { + sal_Int32 nSrcIndex; + sal_Int32 nDeleted = 0; + + /* if pTmp is not already allocated, copy ustrSystemPath for modification */ + if( NULL == pTmp ) + rtl_uString_newFromString( &pTmp, ustrSystemPath ); + + /* adapt index to pTmp */ + nIndex += pTmp->length - ustrSystemPath->length; + + /* remove all occurances of '//' */ + for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ ) + { + if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) ) + nDeleted++; + else + pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex]; + } + + /* adjust length member */ + pTmp->length -= nDeleted; + } + + if( NULL == pTmp ) + rtl_uString_assign( &pTmp, ustrSystemPath ); + + /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ + /* + OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); + */ + + /* file URLs must be URI encoded */ + rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL ); + + rtl_uString_release( pTmp ); + + /* absolute urls should start with 'file://' */ + if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] ) + { + rtl_uString *pProtocol = NULL; + + rtl_uString_newFromAscii( &pProtocol, "file://" ); + rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL ); + rtl_uString_release( pProtocol ); + } + + return osl_File_E_None; +#endif +} + +//############################################# +oslFileError SAL_CALL _osl_getSystemPathFromFileURL( rtl_uString *strURL, rtl_uString **pustrPath, sal_Bool bAllowRelative ) +{ + rtl_String *strUTF8 = NULL; + rtl_uString *strDecodedURL = NULL; + rtl_uString *strTempPath = NULL; + const sal_Unicode *pDecodedURL; + sal_uInt32 nDecodedLen; + sal_Bool bValidEncoded; + oslFileError nError = osl_File_E_INVAL; /* Assume failure */ + + /* If someone hasn't encoded the complete URL we convert it to UTF8 now to prevent from + having a mixed encoded URL later */ + + rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); + + /* If the length of strUTF8 and strURL differs it indicates that the URL was not correct encoded */ + + OSL_ENSURE_FILE( + strUTF8->length == strURL->length || + 0 != rtl_ustr_ascii_shortenedCompare_WithLength( strURL->buffer, strURL->length, "file:\\\\", 7 ) + ,"osl_getSystemPathFromFileURL: \"%s\" is not encoded !!!", strURL ); + + bValidEncoded = _osl_decodeURL( strUTF8, &strDecodedURL ); + + /* Release the encoded UTF8 string */ + + rtl_string_release( strUTF8 ); + + + if ( bValidEncoded ) + { + /* Replace backslashes and pipes */ + + rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '/', '\\' ); + rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '|', ':' ); + + pDecodedURL = rtl_uString_getStr( strDecodedURL ); + nDecodedLen = rtl_uString_getLength( strDecodedURL ); + + /* Must start with "file://" */ + + if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\", 7 ) ) + { + sal_uInt32 nSkip; + + if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\\\", 8 ) ) + nSkip = 8; + else if ( + 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\localhost\\", 17 ) || + 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\127.0.0.1\\", 17 ) + ) + nSkip = 17; + else + nSkip = 5; + + /* Indicates local root */ + if ( nDecodedLen == nSkip ) + rtl_uString_newFromStr_WithLength( &strTempPath, (const sal_Unicode*)WSTR_SYSTEM_ROOT_PATH, ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 ); + else + rtl_uString_newFromStr_WithLength( &strTempPath, pDecodedURL + nSkip, nDecodedLen - nSkip ); + + if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_ELLIPSE ) ) + nError = osl_File_E_None; + } + else if ( bAllowRelative ) /* This maybe a relative file URL */ + { + rtl_uString_assign( &strTempPath, strDecodedURL ); + + if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE | VALIDATEPATH_ALLOW_ELLIPSE ) ) + nError = osl_File_E_None; + } + /* + else + OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL ); + */ + + } + + if ( strDecodedURL ) + rtl_uString_release( strDecodedURL ); + + if ( osl_File_E_None == nError ) + rtl_uString_assign( pustrPath, strTempPath ); + + if ( strTempPath ) + rtl_uString_release( strTempPath ); + + /* + OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL ); + */ + + return nError; +} + +/****************************************************************************/ +/* osl_getSystemPathFromFileURL */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath ) +{ + return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, sal_True ); +#if 0 + sal_Int32 nIndex = 0; + rtl_uString * pTmp = NULL; + + sal_Unicode encodedSlash[3] = { '%', '2', 'F' }; + + /* temporary hack: if already system path, return ustrFileURL */ + /* + if( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) + { + OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" ); + rtl_uString_assign( pustrSystemPath, ustrFileURL ); + return osl_File_E_None; + } + */ + + /* a valid file url may not start with '/' */ + if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) ) + { + return osl_File_E_INVAL; + } + + /* search for encoded slashes (%2F) and decode every single token if we find one */ + if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) ) + { + rtl_uString * ustrPathToken = NULL; + sal_Int32 nOffset = 7; + + do + { + nOffset += nIndex; + + /* break url down in '/' devided tokens tokens */ + nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' ); + + /* copy token to new string */ + rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset, + -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ ); + + /* decode token */ + rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); + + /* the result should not contain any '/' */ + if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) ) + { + rtl_uString_release( pTmp ); + rtl_uString_release( ustrPathToken ); + + return osl_File_E_INVAL; + } + + } while( -1 != nIndex ); + + /* release temporary string and restore index variable */ + rtl_uString_release( ustrPathToken ); + nIndex = 0; + } + + /* protocol and server should not be encoded, so decode the whole string */ + rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); + + /* check if file protocol specified */ + /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ + if( 7 <= pTmp->length ) + { + rtl_uString * pProtocol = NULL; + rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 ); + + /* protocol is case insensitive */ + rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length ); + + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) ) + nIndex = 7; + + rtl_uString_release( pProtocol ); + } + + /* skip "localhost" or "127.0.0.1" if "file://" is specified */ + /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ + if( nIndex && ( 10 <= pTmp->length - nIndex ) ) + { + rtl_uString * pServer = NULL; + rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 ); + + /* server is case insensitive */ + rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length ); + + if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) ) + { + /* don't exclude the '/' */ + nIndex += 9; + } + + rtl_uString_release( pServer ); + } + + if( nIndex ) + rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex ); + + /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ + if( (sal_Unicode) '~' == pTmp->buffer[0] ) + { + /* check if another user is specified */ + if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) ) + { + rtl_uString *pTmp2 = NULL; + + /* osl_getHomeDir returns file URL */ + osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 ); + + /* remove "file://" prefix */ + rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 ); + + /* replace '~' in original string */ + rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 ); + rtl_uString_release( pTmp2 ); + } + + else + { + /* FIXME: replace ~user with users home directory */ + return osl_File_E_INVAL; + } + } + + /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ + /* + OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); + */ + + *pustrSystemPath = pTmp; + return osl_File_E_None; +#endif // 0 +} + + +/**************************************************************************** + * osl_getSystemPathFromFileURL_Ex - helper function + * clients may specify if they want to accept relative + * URLs or not + ****************************************************************************/ + +oslFileError osl_getSystemPathFromFileURL_Ex( + rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative) +{ + return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, bAllowRelative); +#if 0 + rtl_uString* temp = 0; + oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp); + + if (osl_File_E_None == osl_error) + { + if (bAllowRelative + || (UNICHAR_SLASH == temp->buffer[0]) + || (UNICHAR_COLON == temp->buffer[1] && UNICHAR_SLASH == temp->buffer[2])) + { + *pustrSystemPath = temp; + } + else + { + rtl_uString_release(temp); + osl_error = osl_File_E_INVAL; + } + } + + return osl_error; +#endif +} + +namespace /* private */ +{ + +#if 0 // YD + + /****************************************************** + * Helper function, return a pinter to the final '\0' + * of a string + ******************************************************/ + + sal_Unicode* ustrtoend(sal_Unicode* pStr) + { + return (pStr + rtl_ustr_getLength(pStr)); + } + + /********************************************* + + ********************************************/ + sal_Unicode* ustrcpy(const sal_Unicode* s, sal_Unicode* d) + { + const sal_Unicode* sc = s; + sal_Unicode* dc = d; + + while ((*dc++ = *sc++)) + /**/; + + return d; + } + + /********************************************* + + ********************************************/ + + sal_Unicode* ustrncpy(const sal_Unicode* s, sal_Unicode* d, unsigned int n) + { + const sal_Unicode* sc = s; + sal_Unicode* dc = d; + unsigned int i = n; + + while (i--) + *dc++ = *sc++; + + if (n) + *dc = 0; + + return d; + } + + /********************************************* + + ********************************************/ + + sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d) + { + sal_Unicode* p = ustrtoend(d); + *p++ = chr; + *p = 0; + return d; + } + + /********************************************* + + ********************************************/ + + sal_Unicode* ustrcat(const sal_Unicode* s, sal_Unicode* d) + { + sal_Unicode* dc = ustrtoend(d); + ustrcpy(s, dc); + return d; + } + + /****************************************************** + * + ******************************************************/ + + bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr) + { + sal_Unicode* p = ustrtoend(pStr); + if (p > pStr) + p--; + return (*p == Chr); + } + + /****************************************************** + * Ensure that the given string has the specified last + * character if necessary append it + ******************************************************/ + + sal_Unicode* _strensurelast(sal_Unicode* pStr, sal_Unicode Chr) + { + if (!_islastchr(pStr, Chr)) + ustrchrcat(Chr, pStr); + return pStr; + } + + /****************************************************** + * Remove the last part of a path, a path that has + * only a '/' or no '/' at all will be returned + * unmodified + ******************************************************/ + + sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath) + { + /* we always may skip -2 because we + may at least stand on a '/' but + either there is no other character + before this '/' or it's another + character than the '/' + */ + sal_Unicode* p = ustrtoend(aPath) - 2; + + // move back to the next path separator + // or to the start of the string + while ((p > aPath) && (*p != UNICHAR_SLASH)) + p--; + + if (p >= aPath) + { + if (UNICHAR_SLASH == *p) + { + p++; + *p = '\0'; + } + else + { + *p = '\0'; + } + } + + return aPath; + } + + /****************************************************** + * + ******************************************************/ + + oslFileError _osl_resolvepath( + /*inout*/ sal_Unicode* path, + /*inout*/ sal_Unicode* current_pos, + /*in */ sal_Unicode* sentinel, + /*inout*/ bool* failed) + { + oslFileError ferr = osl_File_E_None; + + if (!*failed) + { + char unresolved_path[PATH_MAX]; + if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path))) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + char resolved_path[PATH_MAX]; + if (realpath(unresolved_path, resolved_path)) + { + if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX)) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + current_pos = ustrtoend(path) - 1; + } + else + { + if (EACCES == errno || ENOTDIR == errno || ENOENT == errno) + *failed = true; + else + ferr = oslTranslateFileError(OSL_FET_ERROR, errno); + } + } + + return ferr; + } + + /****************************************************** + * Works even with non existing paths. The resulting + * path must not exceed PATH_MAX else + * osl_File_E_NAMETOOLONG is the result + ******************************************************/ + + oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path) + { + // the given unresolved path must not exceed PATH_MAX + if (unresolved_path.getLength() >= (PATH_MAX - 2)) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + sal_Unicode path_resolved_so_far[PATH_MAX]; + const sal_Unicode* punresolved = unresolved_path.getStr(); + sal_Unicode* presolvedsf = path_resolved_so_far; + + // reserve space for leading '/' and trailing '\0' + // do not exceed this limit + sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2; + + // if realpath fails with error ENOTDIR, EACCES or ENOENT + // we will not call it again, because _osl_realpath should also + // work with non existing directories etc. + bool realpath_failed = false; + oslFileError ferr; + + path_resolved_so_far[0] = '\0'; + + while (*punresolved != '\0') + { + // ignore '/.' , skip one part back when '/..' + + if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf)) + { + if ('\0' == *(punresolved + 1)) + { + punresolved++; + continue; + } + else if (UNICHAR_SLASH == *(punresolved + 1)) + { + punresolved += 2; + continue; + } + else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2)))) + { + _rmlastpathtoken(path_resolved_so_far); + + presolvedsf = ustrtoend(path_resolved_so_far) - 1; + + if (UNICHAR_SLASH == *(punresolved + 2)) + punresolved += 3; + else + punresolved += 2; + + continue; + } + else // a file or directory name may start with '.' + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if ('\0' == *punresolved && !realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + sentinel, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + } + } + } + else if (UNICHAR_SLASH == *punresolved) + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if (!realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + sentinel, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + + if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH)) + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(UNICHAR_SLASH, path_resolved_so_far); + } + } + } + else // any other character + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if ('\0' == *punresolved && !realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + sentinel, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + } + } + } + + sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far); + + OSL_ASSERT(len < PATH_MAX); + + resolved_path = rtl::OUString(path_resolved_so_far, len); + + return osl_File_E_None; + } + +#endif // 0 // YD + +} // end namespace private + +#if OSL_DEBUG_LEVEL > 0 + + //##################################################### + void _osl_warnFile( const char *message, rtl_uString *ustrFile ) + { + char szBuffer[2048]; + + if (ustrFile) + { + rtl_String *strFile = NULL; + + rtl_uString2String( &strFile, rtl_uString_getStr( ustrFile ), rtl_uString_getLength( ustrFile ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + snprintf( szBuffer, sizeof(szBuffer), message, strFile->buffer ); + rtl_string_release( strFile ); + + message = szBuffer; + } + OSL_ENSURE( 0, message ); + } + +#endif // OSL_DEBUG_LEVEL > 0 + +/****************************************************** + * osl_getAbsoluteFileURL + ******************************************************/ + +//oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL) +oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL ) +{ + oslFileError eError; + rtl_uString *ustrRelSysPath = NULL; + rtl_uString *ustrBaseSysPath = NULL; + + if ( ustrBaseURL && ustrBaseURL->length ) + { + eError = _osl_getSystemPathFromFileURL( ustrBaseURL, &ustrBaseSysPath, sal_False ); + OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" ); + + eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_True ); + } + else + { + eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_False ); + OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" ); + } + + if ( !eError ) + { + CHAR szBuffer[_MAX_PATH]; + CHAR szRelSysPath[_MAX_PATH]; + CHAR szCurrentDir[_MAX_PATH]; + int result; + char* cwd; + int rc; + +/*@@@ToDo + Bad, bad hack, this only works if the base path + really exists which is not necessary according + to RFC2396 + The whole FileURL implementation should be merged + with the rtl/uri class. +*/ + if ( ustrBaseSysPath ) + { + CHAR szBaseSysPath[_MAX_PATH]; + + if (!g_CurrentDirectoryMutex) + g_CurrentDirectoryMutex = osl_createMutex(); + + osl_acquireMutex( g_CurrentDirectoryMutex ); + + cwd = getcwd( szCurrentDir, sizeof(szCurrentDir) ); + UnicodeToText( szBaseSysPath, sizeof(szBaseSysPath), ustrBaseSysPath->buffer, ustrBaseSysPath->length); + rc = chdir( szBaseSysPath); + } + + UnicodeToText( szRelSysPath, sizeof(szRelSysPath), ustrRelSysPath->buffer, ustrRelSysPath->length); + result = !_abspath( szBuffer, szRelSysPath, sizeof(szBuffer)); + + if ( ustrBaseSysPath ) + { + rc = chdir( szCurrentDir ); + + osl_releaseMutex( g_CurrentDirectoryMutex ); + } + + if ( result ) + { + rtl_uString *ustrAbsSysPath = NULL; + + oslMakeUStrFromPsz( szBuffer, &ustrAbsSysPath); + + eError = osl_getFileURLFromSystemPath( ustrAbsSysPath, pustrAbsoluteURL ); + + if ( ustrAbsSysPath ) + rtl_uString_release( ustrAbsSysPath ); + } + else + eError = osl_File_E_INVAL; + } + + if ( ustrBaseSysPath ) + rtl_uString_release( ustrBaseSysPath ); + + if ( ustrRelSysPath ) + rtl_uString_release( ustrRelSysPath ); + + return eError; +#if 0 + FileBase::RC rc; + rtl::OUString unresolved_path; + + rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path); + + if(FileBase::E_None != rc) + return oslFileError(rc); + + if (systemPathIsRelativePath(unresolved_path)) + { + rtl::OUString base_path; + rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False); + + if (FileBase::E_None != rc) + return oslFileError(rc); + + rtl::OUString abs_path; + systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path); + + unresolved_path = abs_path; + } + + rtl::OUString resolved_path; + rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path); + + if (FileBase::E_None == rc) + { + rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL); + OSL_ASSERT(FileBase::E_None == rc); + } + + return oslFileError(rc); +#endif // 0 +} + + +namespace /* private */ +{ + + /********************************************* + No separate error code if unicode to text + conversion or getenv fails because for the + caller there is no difference why a file + could not be found in $PATH + ********************************************/ + + bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result) + { + bool bfound = false; + rtl::OUString path = rtl::OUString::createFromAscii("PATH"); + rtl::OUString env_path; + + if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData)) + bfound = osl::searchPath(file_path, env_path, result); + + return bfound; + } + + /********************************************* + No separate error code if unicode to text + conversion or getcwd fails because for the + caller there is no difference why a file + could not be found in CDW + ********************************************/ + + bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result) + { + bool bfound = false; + rtl::OUString cwd_url; + + if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData)) + { + rtl::OUString cwd; + FileBase::getSystemPathFromFileURL(cwd_url, cwd); + bfound = osl::searchPath(file_path, cwd, result); + } + return bfound; + } + + /********************************************* + + ********************************************/ + + bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result) + { + return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result)); + } + +} // end namespace private + + +/**************************************************************************** + * osl_searchFileURL + ***************************************************************************/ + +oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL) +{ + OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter"); + + FileBase::RC rc; + rtl::OUString file_path; + + // try to interpret search path as file url else assume it's a system path list + rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path); + if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc)) + file_path = ustrFilePath; + else if (FileBase::E_None != rc) + return oslFileError(rc); + + bool bfound = false; + rtl::OUString result; + + if (find_in_searchPath(file_path, ustrSearchPath, result) || + find_in_PATH(file_path, result) || + find_in_CWD(file_path, result)) + { + rtl::OUString resolved; + + if (osl::realpath(result, resolved)) + { +#if OSL_DEBUG_LEVEL > 0 + oslFileError osl_error = +#endif + osl_getFileURLFromSystemPath(resolved.pData, pustrURL); + OSL_ASSERT(osl_File_E_None == osl_error); + bfound = true; + } + } + return bfound ? osl_File_E_None : osl_File_E_NOENT; +} + + +/**************************************************************************** + * FileURLToPath + ***************************************************************************/ + +oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath); + + if(osl_File_E_None != osl_error) + return osl_error; + + osl_systemPathRemoveSeparator(ustrSystemPath); + + /* convert unicode path to text */ + if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length)) + osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); + + rtl_uString_release(ustrSystemPath); + + return osl_error; +} diff --git a/sal/osl/os2/file_url.h b/sal/osl/os2/file_url.h new file mode 100644 index 000000000000..052858503b24 --- /dev/null +++ b/sal/osl/os2/file_url.h @@ -0,0 +1,183 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + /*************************************************** + * Internal header file, declares all functions + * that are not part of the offical API and are + * not defined in the osl header files + **************************************************/ + + #ifndef _FILE_URL_H_ + #define _FILE_URL_H_ + + #ifndef _FILE_H_ + #include <osl/file.h> + #endif + + +/*************************************************** + * constants + **************************************************/ + +#define _tcslen(a) wcslen((const wchar_t *) a) +#define _tcsspn(a,b) wcsspn((const wchar_t *) a, (const wchar_t *) b) +#define _istalpha(a) iswalpha((wint_t) a) + +const sal_Unicode UNICHAR_SLASH = ((sal_Unicode)'/'); +const sal_Unicode UNICHAR_COLON = ((sal_Unicode)':'); +const sal_Unicode UNICHAR_DOT = ((sal_Unicode)'.'); + +#define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0]))) + +#if OSL_DEBUG_LEVEL > 0 +#define OSL_ENSURE_FILE( cond, msg, file ) ( (cond) ? (void)0 : _osl_warnFile( msg, file ) ) +#else +#define OSL_ENSURE_FILE( cond, msg, file ) ((void)0) +#endif + +typedef sal_Unicode TCHAR; +typedef sal_Unicode *LPTSTR; +typedef const sal_Unicode *LPCTSTR; +typedef wchar_t *LPWSTR; +typedef const wchar_t *LPCWSTR; +typedef sal_Unicode DWORD; +#define WINAPI + +#define CHARSET_SEPARATOR L"\\/" +#define WSTR_SYSTEM_ROOT_PATH L"\\\\.\\" + + +/****************************************************************************** + * + * Data Type Definition + * + ******************************************************************************/ + +#define PATHTYPE_ERROR 0 +#define PATHTYPE_RELATIVE 1 +#define PATHTYPE_ABSOLUTE_UNC 2 +#define PATHTYPE_ABSOLUTE_LOCAL 3 +#define PATHTYPE_MASK_TYPE 0xFF +#define PATHTYPE_IS_VOLUME 0x0100 +#define PATHTYPE_IS_SERVER 0x0200 + +#define VALIDATEPATH_NORMAL 0x0000 +#define VALIDATEPATH_ALLOW_WILDCARDS 0x0001 +#define VALIDATEPATH_ALLOW_ELLIPSE 0x0002 +#define VALIDATEPATH_ALLOW_RELATIVE 0x0004 +#define VALIDATEPATH_ALLOW_UNC 0x0008 + +typedef struct { + UINT uType; + rtl_uString* ustrDrive; + rtl_uString* ustrFilePath; /* holds native directory path */ + int d_attr; /* OS/2 file attributes */ + int nRefCount; +}DirectoryItem_Impl; + +#define DIRECTORYTYPE_LOCALROOT 0 +#define DIRECTORYTYPE_NETROOT 1 +#define DIRECTORYTYPE_NETRESORCE 2 +#define DIRECTORYTYPE_FILESYSTEM 3 + +#define DIRECTORYITEM_DRIVE 0 +#define DIRECTORYITEM_FILE 1 +#define DIRECTORYITEM_SERVER 2 + +typedef struct +{ + UINT uType; + rtl_uString* ustrPath; /* holds native directory path */ + DIR* pDirStruct; + ULONG ulDriveMap; + ULONG ulNextDrive; + ULONG ulNextDriveMask; +} DirectoryImpl; + +/* Different types of paths */ +typedef enum _PATHTYPE +{ + PATHTYPE_SYNTAXERROR = 0, + PATHTYPE_NETROOT, + PATHTYPE_NETSERVER, + PATHTYPE_VOLUME, + PATHTYPE_FILE +} PATHTYPE; + +DWORD WINAPI IsValidFilePath(LPCTSTR, LPCTSTR*, DWORD); + +typedef struct +{ + rtl_uString* ustrFilePath; /* holds native file path */ + int fd; + sal_Bool bLocked; +} oslFileHandleImpl; + + +typedef struct _oslVolumeDeviceHandleImpl +{ + sal_Char pszMountPoint[PATH_MAX]; + sal_Char pszFilePath[PATH_MAX]; + sal_Char pszDevice[PATH_MAX]; + sal_Char ident[4]; + sal_uInt32 RefCount; +} oslVolumeDeviceHandleImpl; + +/* OS error to errno values mapping table */ +struct errentry { + unsigned long oscode; /* OS return value */ + int errnocode; /* System V error code */ +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************** +* _osl_getSystemPathFromFileURL +*************************************************/ + +#define FURL_ALLOW_RELATIVE sal_True +#define FURL_DENY_RELATIVE sal_False + +oslFileError osl_getSystemPathFromFileURL_Ex(rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative); + +/************************************************** +* FileURLToPath +*************************************************/ + +oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL); + + +#ifdef __cplusplus +} +#endif + + +#endif /* #define _FILE_URL_H_ */ + diff --git a/sal/osl/os2/helpers/debug.h b/sal/osl/os2/helpers/debug.h new file mode 100644 index 000000000000..83edca5db676 --- /dev/null +++ b/sal/osl/os2/helpers/debug.h @@ -0,0 +1,1779 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* + *@@sourcefile debug.h: + * header file for debug.c (exception handling and debugging). + * See remarks there. + * + * Note: Version numbering in this file relates to XWorkplace version + * numbering. + * + *@@changed V0.9.0: included contents of newexe.h + * + *@@include #define INCL_BASE + *@@include #include <os2.h> + *@@include #include <stdio.h> + *@@include #include "helpers\debug.h" + */ + +/* + * This file incorporates code from the following: + * -- Marc Fiammante, John Currier, Kim Rasmussen, + * Anthony Cruise (EXCEPT3.ZIP package for a generic + * exception handling DLL, available at Hobbes). + * + * This file Copyright (C) 1992-99 Ulrich M�ller, + * Kim Rasmussen, + * Marc Fiammante, + * John Currier, + * Anthony Cruise. + * + * 2009-06-15 published under LGPL3 with Ulrich M�ller permission. + * + */ + +#ifndef DEBUG_HEADER_INCLUDED + #define DEBUG_HEADER_INCLUDED + + /******************************************************************** + * + * SYM file declarations + * + ********************************************************************/ + + // Pointer means offset from beginning of file or beginning of struct + #pragma pack(1) + + typedef struct + { + unsigned short int ppNextMap; // paragraph pointer to next map + unsigned char bFlags; // symbol types + unsigned char bReserved1; // reserved + unsigned short int pSegEntry; // segment entry point value + unsigned short int cConsts; // count of constants in map + unsigned short int pConstDef; // pointer to constant chain + unsigned short int cSegs; // count of segments in map + unsigned short int ppSegDef; // paragraph pointer to first segment + unsigned char cbMaxSym; // maximum symbol-name length + unsigned char cbModName; // length of module name + char achModName[1]; // cbModName Bytes of module-name member + } MAPDEF; + + typedef struct + { + unsigned short int ppNextMap; // always zero + unsigned char release; // release number (minor version number) + unsigned char version; // major version number + } LAST_MAPDEF; + + typedef struct + { + unsigned short int ppNextSeg; // paragraph pointer to next segment + unsigned short int cSymbols; // count of symbols in list + unsigned short int pSymDef; // offset of symbol chain + unsigned short int wReserved1; // reserved + unsigned short int wReserved2; // reserved + unsigned short int wReserved3; // reserved + unsigned short int wReserved4; // reserved + unsigned char bFlags; // symbol types; bit 0 signals 32-bit (*UM) + unsigned char bReserved1; // reserved + unsigned short int ppLineDef; // offset of line number record + unsigned char bReserved2; // reserved + unsigned char bReserved3; // reserved + unsigned char cbSegName; // length of segment name + char achSegName[1]; /* cbSegName Bytes of segment-name member*/ + } SEGDEF; + + typedef struct + { + unsigned short int wSymVal; // symbol address or constant + unsigned char cbSymName; // length of symbol name + char achSymName[1]; // cbSymName Bytes of symbol-name member + } SYMDEF16; + + typedef struct + { + unsigned int wSymVal; // symbol address or constant + unsigned char cbSymName; // length of symbol name + char achSymName[1]; // cbSymName Bytes of symbol-name member + } SYMDEF32; + + typedef struct + { + unsigned short int ppNextLine; // ptr to next linedef (0 if last) + unsigned short int wReserved1; // reserved + unsigned short int pLines; // pointer to line numbers + unsigned short int cLines; // reserved + unsigned char cbFileName; // length of filename + char achFileName[1];// cbFileName Bytes of filename + } LINEDEF; + + typedef struct + { + unsigned short int wCodeOffset; // executable offset + unsigned short int dwFileOffset; // source offset + } LINEINF; + + #define SEGDEFOFFSET(MapDef) (MapDef.ppSegDef*16) + #define NEXTSEGDEFOFFSET(SegDef) (SegDef.ppNextSeg*16) + + #define ASYMPTROFFSET(SegDefOffset,Segdef) (SegDefOffset+SegDef.pSymDef) + #define SYMDEFOFFSET(SegDefOffset,SegDef,n) (ASYMPTROFFSET(SegDefOffset,SegDef)+(n)*(sizeof(unsigned short int))) + + #define ACONSTPTROFFSET(MapDef) (MapDef.ppConstDef) + #define CONSTDEFOFFSET(MapDef,n) ((MapDef.ppConstDef)+(n)*(sizeof(unsigned short int))) + + #define LINEDEFOFFSET(SegDef) (SegDef.ppLineDef*16) + #define NEXTLINEDEFOFFSET(LineDef) (LineDef.ppNextLine*16) + #define LINESOFFSET(LinedefOffset,LineDef) ((LinedefOffset)+LineDef.pLines) + + /******************************************************************** + * + * EXE declarations taken from exe.h + * + ********************************************************************/ + + #ifndef WORD + typedef unsigned short WORD; + #endif + + typedef WORD bbmask; + + struct exe { + WORD eid; // contains EXEID, below + WORD elast; // # of bytes in last page + WORD epagsiz; // # of pages in whole file + WORD erelcnt; // # of relocation entrys + WORD ehdrsiz; // size of header, in paragraphs + WORD eminfre; // min # of free paragraphs needed + WORD emaxfre; // max # of free paragraphs needed + WORD eiSS; // initial SS value + WORD eiSP; // initial SP value + WORD enegsum; // negative sum of entire file + WORD eiIP; // initial IP value + WORD eiCS; // initial CS value + WORD ereloff; // offset in file of relocation table + WORD eovlnum; // number of the overlay + + /* the following fields may not be present. + * ereloff = 28 not present + * = 30 exe.ever present and valid + * = 32 exe.ever field contains garbage + * ereloff > 32 exe.ever present and valid + * = 0 if "don't know" + */ + + WORD ever; // version # of producing linker + WORD dumy; // unused + + /* the following fields may not be present - if the exe.ereloff + * value encompasses the fields then they are present and valid. + */ + + bbmask ebb; // behavior bits + WORD dumy2[7]; // must be 0 until defined + }; + + + #define EXEID 0x5a4d // magic ID value + + /******************************************************************** + * + * Object Module Format (OMF) declarations + * + ********************************************************************/ + + struct exehdr_rec + { + BYTE signature[2]; // Must be "MZ" + USHORT image_len; // Image Length + USHORT pages; // Pages + USHORT reloc_items; // Relocation table items + USHORT min_paragraphs; // Mininum 16-bytes paragraphs + USHORT max_paragraphs; // Maximum 16-bytes paragraphs + USHORT stack_pos; // Stack position + USHORT offset_in_sp; // Offset in SP + USHORT checksum; // Checksum + USHORT offset_in_ip; // Offset in IP + USHORT code_pos; // Code segment pos. + USHORT reloc_item_pos; // Position of first relocation item + USHORT overlay_number; // Overlay number + BYTE unused[8]; // Unused bytes + USHORT oem_id; // OEM Identifier + BYTE oem_info[24]; // OEM Info + ULONG lexe_offset; // Offset to linear header + }; + + struct lexehdr_rec + { + BYTE signature[2]; // Must be "LX" + BYTE b_ord; // Byte ordering + BYTE w_ord; // Word ordering + ULONG format_level; // Format level + USHORT cpu_type; // CPU Type + USHORT os_type; // Operating system + ULONG module_version; // Module version + ULONG mod_flags; // Module flags + ULONG mod_pages; // Module pages + ULONG EIP_object; // EIP Object no. + ULONG EIP; // EIP Value + ULONG ESP_object; // ESP Object no + ULONG ESP; // ESP Value + ULONG page_size; // Page size + ULONG page_ofs_shift; // Page offset shift + ULONG fixup_sect_size; // Fixup section size + ULONG fixup_sect_checksum; // Fixup section checksum + ULONG loader_sect_size; // Loader section size + ULONG loader_sect_checksum; // Loader section checksum + ULONG obj_table_ofs; // Object table offset + ULONG obj_count; // Object count + ULONG obj_page_tab_ofs; // Object page table offset + ULONG obj_iter_page_ofs; // Object iteration pages offset + ULONG res_tab_ofs; // Resource table offset + ULONG res_table_entries; // Resource table entries + ULONG res_name_tab_ofs; // Resident name table offset; + ULONG ent_tab_ofs; // Entry table offset + ULONG mod_dir_ofs; // Module directives offset + ULONG mod_dir_count; // Number of module directives + ULONG fixup_page_tab_ofs; // Fixup page table offset + ULONG fixup_rec_tab_ofs; // Fixup record table offset + ULONG imp_tab_ofs; // Import module table offset + ULONG imp_mod_entries; // Import module entries + ULONG imp_proc_tab_ofs; // Import proc table offset + ULONG per_page_check_ofs; // Per page checksum offset + ULONG data_page_offset; // Data pages offset + ULONG preload_page_count; // Preload pages count + ULONG nonres_tab_ofs; // Nonresident name table offset + ULONG nonres_tab_len; // Nonresident name table len + ULONG nonres_tab_check; // Nonresident tables checksum + ULONG auto_ds_objectno; // Auto DS object number + ULONG debug_info_ofs; // Debug info offset + ULONG debug_info_len; // Debug info length + ULONG inst_preload_count; // Instance preload count + ULONG inst_demand_count; // Instance demand count + ULONG heapsize; // Heap size + ULONG stacksize; // Stack size + }; + + struct debug_head_rec + { + BYTE signature[3]; // Debug signature + BYTE type; // Debug info type + }; + + struct dir_inf_rec + { + USHORT dirstruct_size; // Size of directory structure + USHORT number_of_entries; // Number of dnt_rec's in the array + USHORT unknown; // Unknown data + // Followed by an array of dnt_rec structures + }; + + struct dnt_rec + { + USHORT subsect_type; // sst Subsection type + USHORT mod_index; // Module index (1-based) + ULONG offset; // Offset of start of section + ULONG size; // Size of section + }; + + // Modules subsection + struct modules_rec + { + USHORT code_seg_base; // Code segment base + ULONG code_seg_offset; // Code segment offset + ULONG code_seg_len; // Code segment length + USHORT overlay_no; // Overlay number + USHORT lib_idx; // Index into library section or 0 + BYTE segments; // Number of segments + BYTE reserved; + BYTE debug_style[2]; // "HL" for HLL, "CV" or 0 for CodeView + BYTE debug_version[2]; // 00 01 or 00 03 for HLL, 00 00 for CV + BYTE name_len; // Length of name (which follows) + }; + + // Publics subsection + struct publics_rec + { + ULONG offset; // Offset + USHORT segment; // Segment + USHORT type; // Type index + BYTE name_len; // Length of name (wich follows) + }; + + #if 0 + // Linenumbers header + struct linhead_rec + { + BYTE id; // 0x95 for flat mem, 32 bit progs + USHORT length; // Record length + USHORT base_group; // Base group + USHORT base_segment; // Base segment + }; + #endif + + // First linenumber record + struct linfirst_rec + { + USHORT lineno; // Line number (0) + BYTE entry_type; // Entry type + BYTE reserved; // Reserved + USHORT entries_count; // Number of table entries + USHORT segment_no; // Segment number + ULONG filename_tabsize; // File names table size + }; + + // Source line numbers + struct linsource_rec + { + USHORT source_line; // Source file line number + USHORT source_idx; // Source file index + ULONG offset; // Offset into segment + }; + + // Listing statement numbers + struct linlist_rec + { + ULONG list_line; // Listing file linenumber + ULONG statement; // Listing file statement number + ULONG offset; // Offset into segment + }; + + // Source and Listing statement numbers + struct linsourcelist_rec + { + USHORT source_line; // Source file line number + USHORT source_idx; // Source file index + ULONG list_line; // Listing file linenumber + ULONG statement; // Listing file statement number + ULONG offset; // Offset into segment + }; + + // Path table + struct pathtab_rec + { + ULONG offset; // Offset into segment + USHORT path_code; // Path code + USHORT source_idx; // Source file index + }; + + // File names table + struct filenam_rec + { + ULONG first_char; // First displayable char in list file + ULONG disp_chars; // Number of displayable chars in list line + ULONG filecount; // Number of source/listing files + }; + + // Symbol types + #define SYM_BEGIN 0x00 // Begin block + #define SYM_PROC 0x01 // Function + #define SYM_END 0x02 // End block of function + #define SYM_AUTO 0x04 // Auto variable + #define SYM_STATIC 0x05 // Static variable + #define SYM_LABEL 0x0B // Label + #define SYM_WITH 0x0C // With start symbol (not used) + #define SYM_REG 0x0D // Register variable + #define SYM_CONST 0x0E // Constant + #define SYM_ENTRY 0x0F // Secondary entry (not in C) + #define SYM_SKIP 0x10 // For incremental linking (not used) + #define SYM_CHANGESEG 0x11 // Change segment (#pragma alloc_text) + #define SYM_TYPEDEF 0x12 // Typedef variable + #define SYM_PUBLIC 0x13 // Public reference + #define SYM_MEMBER 0x14 // Member of minor or major structure + #define SYM_BASED 0x15 // Based variable + #define SYM_TAG 0x16 // Tag in struct, union, enum ... + #define SYM_TABLE 0x17 // Table (used in RPG - not C) + #define SYM_MAP 0x18 // Map variable (extern in C) + #define SYM_CLASS 0x19 // Class symbol (C++) + #define SYM_MEMFUNC 0x1A // Member function + #define SYM_AUTOSCOPE 0x1B // Scoped auto for C++ (not used) + #define SYM_STATICSCOPE 0x1C // scoped static for C++ (not used) + #define SYM_CPPPROC 0x1D // C++ Proc + #define SYM_CPPSTAT 0x1E // C++ Static var + #define SYM_COMP 0x40 // Compiler information + + // Symbolic begin record + struct symbegin_rec + { + ULONG offset; // Segment offset + ULONG length; // Length of block + BYTE name_len; // Length of block name + // Block name follows + }; + + // Symbolic auto var record + struct symauto_rec + { + ULONG stack_offset; // Stack offset + USHORT type_idx; // Type index + BYTE name_len; // Length of name + // Var name follows + }; + + // Symbolic procedure record + struct symproc_rec + { + ULONG offset; // Segment offset + USHORT type_idx; // Type index + ULONG length; // Length of procedure + USHORT pro_len; // Length of prologue + ULONG pro_bodylen; // Length of prologue + body + USHORT class_type; // Class type + BYTE near_far; // Near or far + BYTE name_len; // Length of name + // Function name follows + }; + + // Symbolic static var record + struct symstatic_rec + { + ULONG offset; // Segment offset + USHORT segaddr; // Segment address + USHORT type_idx; // Type index + BYTE name_len; // Length of name + // Var name follows + }; + + // Symbolic label var record + struct symlabel_rec + { + ULONG offset; // Segment offset + BYTE near_far; // Near or far + BYTE name_len; // Length of name + // Var name follows + }; + + // Symbolic register var record + struct symreg_rec + { + USHORT type_idx; // Type index + BYTE reg_no; // Register number + BYTE name_len; // Length of name + // Var name follows + }; + + // Symbolic change-segment record + struct symseg_rec + { + USHORT seg_no; // Segment number + }; + + // Symbolic typedef record + struct symtypedef_rec + { + USHORT type_idx; // Type index + BYTE name_len; // Length of name + // Name follows + }; + + // Symbolic public record + struct sympublic_rec + { + ULONG offset; // Segment offset + USHORT segaddr; // Segment address + USHORT type_idx; // Type index + BYTE name_len; // Length of name + // Name follows + }; + + // Symbolic member record + struct symmember_rec + { + ULONG offset; // Offset to subrecord + BYTE name_len; // Length of name + // Name follows + }; + + // Symbolic based record + struct symbased_rec + { + ULONG offset; // Offset to subrecord + USHORT type_idx; // Type index + BYTE name_len; // Length of name + // Name follows + }; + + // Symbolic tag record + struct symtag_rec + { + USHORT type_idx; // Type index + BYTE name_len; // Length of name + // Name follows + }; + + // Symbolic table record + struct symtable_rec + { + ULONG offset; // Segment offset + USHORT segaddr; // Segment address + USHORT type_idx; // Type index + ULONG idx_ofs; // Index offset to subrecord + BYTE name_len; // Length of name + // Name follows + }; + + // Type record + struct type_rec + { + USHORT length; // Length of sub-record + BYTE type; // Sub-record type + BYTE type_qual; // Type qualifier + }; + + // Types + #define TYPE_CLASS 0x40 // Class + #define TYPE_BASECLASS 0x41 // Base class + #define TYPE_FRIEND 0x42 // Friend + #define TYPE_CLASSDEF 0x43 // Class definition + #define TYPE_MEMBERFUNC 0x45 // Member function + #define TYPE_CLASSMEMBER 0x46 // Class member + #define TYPE_REF 0x48 // Reference + #define TYPE_MEMBERPTR 0x49 // Member pointer + #define TYPE_SCALARS 0x51 // Scalars + #define TYPE_SET 0x52 // Set + #define TYPE_ENTRY 0x53 // Entry + #define TYPE_FUNCTION 0x54 // Function + #define TYPE_AREA 0x55 // Area + #define TYPE_LOGICAL 0x56 // Logical + #define TYPE_STACK 0x57 // Stack + #define TYPE_MACRO 0x59 // Macro + #define TYPE_BITSTRING 0x5C // Bit string + #define TYPE_USERDEF 0x5D // User defined + #define TYPE_CHARSTR 0x60 // Character string + #define TYPE_PICTURE 0x61 // Picture + #define TYPE_GRAPHIC 0x62 // Graphic + #define TYPE_FORMATLAB 0x65 // Format label + #define TYPE_FILE 0x67 // File + #define TYPE_SUBRANGE 0x6F // Subrange + #define TYPE_CODELABEL 0x72 // Code label + #define TYPE_PROCEDURE 0x75 // Procedure + #define TYPE_ARRAY 0x78 // Array + #define TYPE_STRUCT 0x79 // Structure / Union / Record + #define TYPE_POINTER 0x7A // Pointer + #define TYPE_ENUM 0x7B // Enum + #define TYPE_LIST 0x7F // List + + // Type userdef + struct type_userdefrec + { + BYTE FID_index; // Field ID + USHORT type_index; // Type index + BYTE FID_string; // String ID + BYTE name_len; // Length of name which follows + }; + + // Type function + struct type_funcrec + { + USHORT params; + USHORT max_params; + BYTE FID_index; // Field ID + USHORT type_index; // Type index of return value + BYTE FID_index1; // String ID + USHORT typelist_index; // Index of list of params + }; + + // Type struct + struct type_structrec + { + ULONG size; // Size of structure + USHORT field_count; // Number of fields in structure + BYTE FID_index; // Field ID + USHORT type_list_idx; // Index to type list + BYTE FID_index1; // Field ID + USHORT type_name_idx; // Index to names / offsets + BYTE dont_know; // Haven't a clue, but it seems to be needed + BYTE name_len; // Length of structure name which follows + }; + + // Type list, type qualifier 1: contains types for structures + // This record is repeated for the number of items in the structure definition + struct type_list1 + { + BYTE FID_index; // Field identifier for index + USHORT type_index; // Type index. + }; + + // Type list, type qualifier 2: contains names and offsets for structure items + // This record is repeated for the number of items in the structure definition + struct type_list2 + { + BYTE FID_string; // String identifier + BYTE name_len; // Length of name which follows + }; + + // Type list, subrecord to the above, contains offset of variable in the structure + struct type_list2_1 + { + BYTE FID_span; // Defines what type of variable follows + union { + BYTE b_len; + USHORT s_len; + ULONG l_len; + } u; + }; + + // Type pointer + struct type_pointerrec + { + BYTE FID_index; // Index identifier + USHORT type_index; // Type index + BYTE FID_string; // String identifier + BYTE name_len; // Length of name which follows + }; + + /******************************************************************** + * + * Prototypes + * + ********************************************************************/ + + BOOL dbgPrintStackFrame(FILE *LogFile, + PSZ pszModuleName, // in: module name (fully q'fied) + ULONG ulObject, + ULONG ulOffset); + + VOID dbgPrintStack(FILE *file, + PUSHORT StackBottom, + PUSHORT StackTop, + PUSHORT Ebp, + PUSHORT ExceptionAddress); + + APIRET APIENTRY DosQueryModFromEIP(HMODULE *phMod, // out: trapping module + ULONG *pulObjNum, // out: object/segment number + ULONG ulBuffLen, // in: sizeof(*pszBuff) + CHAR *pszBuff, // out: module name + ULONG *pulOffset, // out: offset in module + ULONG ulAddress); // in: address to be analyzed + + APIRET APIENTRY DOSQUERYMODFROMEIP(HMODULE * phMod, + ULONG * pObjNum, + ULONG BuffLen, + PCHAR pBuff, + ULONG * pOffset, + PVOID Address); + + typedef ULONG *_Seg16 PULONG16; + APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size); + typedef APIRET16(APIENTRY16 _PFN16) (VOID); + ULONG APIENTRY DosSelToFlat(ULONG); + + APIRET16 APIENTRY16 DOSQPROCSTATUS(ULONG * _Seg16 pBuf, USHORT cbBuf); + + #define CONVERT(fp,QSsel) MAKEP((QSsel),OFFSETOF(fp)) + + #pragma pack() // added V0.9.0 + + + /******************************************************************** + * + * Executable definitions + * + ********************************************************************/ + + #define EXE386 1 + + #ifndef __NEWEXE__ + #define __NEWEXE__ + + #pragma pack(1) + + /*_________________________________________________________________* + | | + | | + | DOS3 .EXE FILE HEADER DEFINITION | + | | + |_________________________________________________________________| + * */ + + + #define EMAGIC 0x5A4D // Old magic number + #define ENEWEXE sizeof(struct exe_hdr) + // Value of E_LFARLC for new .EXEs + #define ENEWHDR 0x003C // Offset in old hdr. of ptr. to new + #define ERESWDS 0x0010 // No. of reserved words (OLD) + #define ERES1WDS 0x0004 // No. of reserved words in e_res + #define ERES2WDS 0x000A // No. of reserved words in e_res2 + #define ECP 0x0004 // Offset in struct of E_CP + #define ECBLP 0x0002 // Offset in struct of E_CBLP + #define EMINALLOC 0x000A // Offset in struct of E_MINALLOC + + /* + *@@ exe_hdr: + * DOS 1, 2, 3 .EXE header. + */ + + struct exe_hdr + { + unsigned short e_magic; // Magic number + unsigned short e_cblp; // Bytes on last page of file + unsigned short e_cp; // Pages in file + unsigned short e_crlc; // Relocations + unsigned short e_cparhdr; // Size of header in paragraphs + unsigned short e_minalloc; // Minimum extra paragraphs needed + unsigned short e_maxalloc; // Maximum extra paragraphs needed + unsigned short e_ss; // Initial (relative) SS value + unsigned short e_sp; // Initial SP value + unsigned short e_csum; // Checksum + unsigned short e_ip; // Initial IP value + unsigned short e_cs; // Initial (relative) CS value + unsigned short e_lfarlc; // File address of relocation table + unsigned short e_ovno; // Overlay number + unsigned short e_res[ERES1WDS];// Reserved words + unsigned short e_oemid; // OEM identifier (for e_oeminfo) + unsigned short e_oeminfo; // OEM information; e_oemid specific + unsigned short e_res2[ERES2WDS];// Reserved words + long e_lfanew; // File address of new exe header + }; + + #define E_MAGIC(x) (x).e_magic + #define E_CBLP(x) (x).e_cblp + #define E_CP(x) (x).e_cp + #define E_CRLC(x) (x).e_crlc + #define E_CPARHDR(x) (x).e_cparhdr + #define E_MINALLOC(x) (x).e_minalloc + #define E_MAXALLOC(x) (x).e_maxalloc + #define E_SS(x) (x).e_ss + #define E_SP(x) (x).e_sp + #define E_CSUM(x) (x).e_csum + #define E_IP(x) (x).e_ip + #define E_CS(x) (x).e_cs + #define E_LFARLC(x) (x).e_lfarlc + #define E_OVNO(x) (x).e_ovno + #define E_RES(x) (x).e_res + #define E_OEMID(x) (x).e_oemid + #define E_OEMINFO(x) (x).e_oeminfo + #define E_RES2(x) (x).e_res2 + #define E_LFANEW(x) (x).e_lfanew + + + /*_________________________________________________________________* + | | + | | + | OS/2 & WINDOWS .EXE FILE HEADER DEFINITION - 286 version | + | | + |_________________________________________________________________| + * */ + + #define NEMAGIC 0x454E // New magic number + #define NERESBYTES 8 // Eight bytes reserved (now) + #define NECRC 8 // Offset into new header of NE_CRC + + /* + *@@ new_exe: + * New Executable (NE) header. + * Follows DOS header in the executable file. + */ + + struct new_exe + { + unsigned short ne_magic; // Magic number NE_MAGIC + unsigned char ne_ver; // Version number + unsigned char ne_rev; // Revision number + unsigned short ne_enttab; // Offset of Entry Table + unsigned short ne_cbenttab; // Number of bytes in Entry Table + long ne_crc; // Checksum of whole file + unsigned short ne_flags; // Flag word + unsigned short ne_autodata; // Automatic data segment number + unsigned short ne_heap; // Initial heap allocation + unsigned short ne_stack; // Initial stack allocation + long ne_csip; // Initial CS:IP setting + long ne_sssp; // Initial SS:SP setting + unsigned short ne_cseg; // Count of file segments + unsigned short ne_cmod; // Entries in Module Reference Table + unsigned short ne_cbnrestab; // Size of non-resident name table + unsigned short ne_segtab; // Offset of Segment Table + unsigned short ne_rsrctab; // Offset of Resource Table + unsigned short ne_restab; // Offset of resident name table + unsigned short ne_modtab; // Offset of Module Reference Table + unsigned short ne_imptab; // Offset of Imported Names Table + long ne_nrestab; // Offset of Non-resident Names Table + unsigned short ne_cmovent; // Count of movable entries + unsigned short ne_align; // Segment alignment shift count + unsigned short ne_cres; // Count of resource entries + unsigned char ne_exetyp; // Target operating system + unsigned char ne_flagsothers; // Other .EXE flags + char ne_res[NERESBYTES]; // Pad structure to 64 bytes + }; + + #pragma pack() + + #define NE_MAGIC(x) (x).ne_magic + #define NE_VER(x) (x).ne_ver + #define NE_REV(x) (x).ne_rev + #define NE_ENTTAB(x) (x).ne_enttab + #define NE_CBENTTAB(x) (x).ne_cbenttab + #define NE_CRC(x) (x).ne_crc + #define NE_FLAGS(x) (x).ne_flags + #define NE_AUTODATA(x) (x).ne_autodata + #define NE_HEAP(x) (x).ne_heap + #define NE_STACK(x) (x).ne_stack + #define NE_CSIP(x) (x).ne_csip + #define NE_SSSP(x) (x).ne_sssp + #define NE_CSEG(x) (x).ne_cseg + #define NE_CMOD(x) (x).ne_cmod + #define NE_CBNRESTAB(x) (x).ne_cbnrestab + #define NE_SEGTAB(x) (x).ne_segtab + #define NE_RSRCTAB(x) (x).ne_rsrctab + #define NE_RESTAB(x) (x).ne_restab + #define NE_MODTAB(x) (x).ne_modtab + #define NE_IMPTAB(x) (x).ne_imptab + #define NE_NRESTAB(x) (x).ne_nrestab + #define NE_CMOVENT(x) (x).ne_cmovent + #define NE_ALIGN(x) (x).ne_align + #define NE_CRES(x) (x).ne_cres + #define NE_RES(x) (x).ne_res + #define NE_EXETYP(x) (x).ne_exetyp + #define NE_FLAGSOTHERS(x) (x).ne_flagsothers + + #define NE_USAGE(x) (WORD)*((WORD *)(x)+1) + #define NE_PNEXTEXE(x) (WORD)(x).ne_cbenttab + #define NE_ONEWEXE(x) (WORD)(x).ne_crc + #define NE_PFILEINFO(x) (WORD)((DWORD)(x).ne_crc >> 16) + + + /* + * Target operating systems + */ + + #define NE_UNKNOWN 0x0 /* Unknown (any "new-format" OS) */ + #define NE_OS2 0x1 /* OS/2 (default) */ + #define NE_WINDOWS 0x2 /* Windows */ + #define NE_DOS4 0x3 /* DOS 4.x */ + #define NE_DEV386 0x4 /* Windows 386 */ + + + /* + * Format of NE_FLAGS(x): + * + * p Not-a-process + * x Unused + * e Errors in image + * x Unused + * b Bound Family/API + * ttt Application type + * f Floating-point instructions + * 3 386 instructions + * 2 286 instructions + * 0 8086 instructions + * P Protected mode only + * p Per-process library initialization + * i Instance data + * s Solo data + */ + #define NENOTP 0x8000 /* Not a process */ + #define NEIERR 0x2000 /* Errors in image */ + #define NEBOUND 0x0800 /* Bound Family/API */ + #define NEAPPTYP 0x0700 /* Application type mask */ + #define NENOTWINCOMPAT 0x0100 /* Not compatible with P.M. Windowing */ + #define NEWINCOMPAT 0x0200 /* Compatible with P.M. Windowing */ + #define NEWINAPI 0x0300 /* Uses P.M. Windowing API */ + #define NEFLTP 0x0080 /* Floating-point instructions */ + #define NEI386 0x0040 /* 386 instructions */ + #define NEI286 0x0020 /* 286 instructions */ + #define NEI086 0x0010 /* 8086 instructions */ + #define NEPROT 0x0008 /* Runs in protected mode only */ + #define NEPPLI 0x0004 /* Per-Process Library Initialization */ + #define NEINST 0x0002 /* Instance data */ + #define NESOLO 0x0001 /* Solo data */ + + /* + * Format of NE_FLAGSOTHERS(x): + * + * 7 6 5 4 3 2 1 0 - bit no + * | | | | + * | | | +---------------- Support for long file names + * | | +------------------ Windows 2.x app runs in prot mode + * | +-------------------- Windows 2.x app gets prop. font + * +------------------------------ WLO appl on OS/2 (markwlo.exe) + * + */ + + #define NELONGNAMES 0x01 + #define NEWINISPROT 0x02 + #define NEWINGETPROPFON 0x04 + #define NEWLOAPPL 0x80 + + + + struct new_seg /* New .EXE segment table entry */ + { + unsigned short ns_sector; /* File sector of start of segment */ + unsigned short ns_cbseg; /* Number of bytes in file */ + unsigned short ns_flags; /* Attribute flags */ + unsigned short ns_minalloc; /* Minimum allocation in bytes */ + }; + + #define NS_SECTOR(x) (x).ns_sector + #define NS_CBSEG(x) (x).ns_cbseg + #define NS_FLAGS(x) (x).ns_flags + #define NS_MINALLOC(x) (x).ns_minalloc + + + /* + * Format of NS_FLAGS(x) + * + * Flag word has the following format: + * + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no + * | | | | | | | | | | | | | | | + * | | | | | | | | | | | | +-+-+--- Segment type DATA/CODE + * | | | | | | | | | | | +--------- Iterated segment + * | | | | | | | | | | +----------- Movable segment + * | | | | | | | | | +------------- Segment can be shared + * | | | | | | | | +--------------- Preload segment + * | | | | | | | +----------------- Execute/read-only for code/data segment + * | | | | | | +------------------- Segment has relocations + * | | | | | +--------------------- Code conforming/Data is expand down + * | | | +--+----------------------- I/O privilege level + * | | +----------------------------- Discardable segment + * | +-------------------------------- 32-bit code segment + * +----------------------------------- Huge segment/GDT allocation requested + * + */ + + #define NSTYPE 0x0007 /* Segment type mask */ + + #ifdef EXE386 + #define NSCODE 0x0000 /* Code segment */ + #define NSDATA 0x0001 /* Data segment */ + #define NSITER 0x0008 /* Iterated segment flag */ + #define NSMOVE 0x0010 /* Movable segment flag */ + #define NSSHARED 0x0020 /* Shared segment flag */ + #define NSPRELOAD 0x0040 /* Preload segment flag */ + #define NSEXRD 0x0080 /* Execute-only (code segment), or + * read-only (data segment) + */ + #define NSRELOC 0x0100 /* Segment has relocations */ + #define NSCONFORM 0x0200 /* Conforming segment */ + #define NSEXPDOWN 0x0200 /* Data segment is expand down */ + #define NSDPL 0x0C00 /* I/O privilege level (286 DPL bits) */ + #define SHIFTDPL 10 /* Left shift count for SEGDPL field */ + #define NSDISCARD 0x1000 /* Segment is discardable */ + #define NS32BIT 0x2000 /* 32-bit code segment */ + #define NSHUGE 0x4000 /* Huge memory segment, length of + * segment and minimum allocation + * size are in segment sector units + */ + #define NSGDT 0x8000 /* GDT allocation requested */ + + #define NSPURE NSSHARED /* For compatibility */ + + #define NSALIGN 9 /* Segment data aligned on 512 byte boundaries */ + + #define NSLOADED 0x0004 /* ns_sector field contains memory addr */ + #endif + + + struct new_segdata /* Segment data */ + { + union + { + struct + { + unsigned short ns_niter; /* number of iterations */ + unsigned short ns_nbytes; /* number of bytes */ + char ns_iterdata; /* iterated data bytes */ + } ns_iter; + struct + { + char ns_data; /* data bytes */ + } ns_noniter; + } ns_union; + }; + + struct new_rlcinfo /* Relocation info */ + { + unsigned short nr_nreloc; /* number of relocation items that */ + }; /* follow */ + + #pragma pack(1) + + + struct new_rlc /* Relocation item */ + { + char nr_stype; /* Source type */ + char nr_flags; /* Flag byte */ + unsigned short nr_soff; /* Source offset */ + union + { + struct + { + char nr_segno; /* Target segment number */ + char nr_res; /* Reserved */ + unsigned short nr_entry; /* Target Entry Table offset */ + } nr_intref; /* Internal reference */ + struct + { + unsigned short nr_mod; /* Index into Module Reference Table */ + unsigned short nr_proc; /* Procedure ordinal or name offset */ + } nr_import; /* Import */ + struct + { + unsigned short nr_ostype; /* OSFIXUP type */ + unsigned short nr_osres; /* reserved */ + } nr_osfix; /* Operating system fixup */ + } nr_union; /* Union */ + }; + + #pragma pack() + + + #define NR_STYPE(x) (x).nr_stype + #define NR_FLAGS(x) (x).nr_flags + #define NR_SOFF(x) (x).nr_soff + #define NR_SEGNO(x) (x).nr_union.nr_intref.nr_segno + #define NR_RES(x) (x).nr_union.nr_intref.nr_res + #define NR_ENTRY(x) (x).nr_union.nr_intref.nr_entry + #define NR_MOD(x) (x).nr_union.nr_import.nr_mod + #define NR_PROC(x) (x).nr_union.nr_import.nr_proc + #define NR_OSTYPE(x) (x).nr_union.nr_osfix.nr_ostype + #define NR_OSRES(x) (x).nr_union.nr_osfix.nr_osres + + + + /* + * Format of NR_STYPE(x) and R32_STYPE(x): + * + * 7 6 5 4 3 2 1 0 - bit no + * | | | | + * +-+-+-+--- source type + * + */ + + #define NRSTYP 0x0f /* Source type mask */ + #define NRSBYT 0x00 /* lo byte (8-bits)*/ + #define NRSSEG 0x02 /* 16-bit segment (16-bits) */ + #define NRSPTR 0x03 /* 16:16 pointer (32-bits) */ + #define NRSOFF 0x05 /* 16-bit offset (16-bits) */ + #define NRPTR48 0x06 /* 16:32 pointer (48-bits) */ + #define NROFF32 0x07 /* 32-bit offset (32-bits) */ + #define NRSOFF32 0x08 /* 32-bit self-relative offset (32-bits) */ + + + /* + * Format of NR_FLAGS(x) and R32_FLAGS(x): + * + * 7 6 5 4 3 2 1 0 - bit no + * | | | + * | +-+--- Reference type + * +------- Additive fixup + */ + + #define NRADD 0x04 /* Additive fixup */ + #define NRRTYP 0x03 /* Reference type mask */ + #define NRRINT 0x00 /* Internal reference */ + #define NRRORD 0x01 /* Import by ordinal */ + #define NRRNAM 0x02 /* Import by name */ + #define NRROSF 0x03 /* Operating system fixup */ + + + #if (EXE386 == 0) + + /* Resource type or name string */ + struct rsrc_string + { + char rs_len; /* number of bytes in string */ + char rs_string[ 1 ]; /* text of string */ + }; + + #define RS_LEN( x ) (x).rs_len + #define RS_STRING( x ) (x).rs_string + + /* Resource type information block */ + struct rsrc_typeinfo + { + unsigned short rt_id; + unsigned short rt_nres; + long rt_proc; + }; + + #define RT_ID( x ) (x).rt_id + #define RT_NRES( x ) (x).rt_nres + #define RT_PROC( x ) (x).rt_proc + + /* Resource name information block */ + struct rsrc_nameinfo + { + /* The following two fields must be shifted left by the value of */ + /* the rs_align field to compute their actual value. This allows */ + /* resources to be larger than 64k, but they do not need to be */ + /* aligned on 512 byte boundaries, the way segments are */ + unsigned short rn_offset; /* file offset to resource data */ + unsigned short rn_length; /* length of resource data */ + unsigned short rn_flags; /* resource flags */ + unsigned short rn_id; /* resource name id */ + unsigned short rn_handle; /* If loaded, then global handle */ + unsigned short rn_usage; /* Initially zero. Number of times */ + /* the handle for this resource has */ + /* been given out */ + }; + + #define RN_OFFSET( x ) (x).rn_offset + #define RN_LENGTH( x ) (x).rn_length + #define RN_FLAGS( x ) (x).rn_flags + #define RN_ID( x ) (x).rn_id + #define RN_HANDLE( x ) (x).rn_handle + #define RN_USAGE( x ) (x).rn_usage + + #define RSORDID 0x8000 /* if high bit of ID set then integer id */ + /* otherwise ID is offset of string from + the beginning of the resource table */ + + /* Ideally these are the same as the */ + /* corresponding segment flags */ + #define RNMOVE 0x0010 /* Moveable resource */ + #define RNPURE 0x0020 /* Pure (read-only) resource */ + #define RNPRELOAD 0x0040 /* Preloaded resource */ + #define RNDISCARD 0xF000 /* Discard priority level for resource */ + + /* Resource table */ + struct new_rsrc + { + unsigned short rs_align; /* alignment shift count for resources */ + struct rsrc_typeinfo rs_typeinfo; + }; + + #define RS_ALIGN( x ) (x).rs_align + + + #endif /* NOT EXE386 */ + + #endif /* __NEWEXE__ */ + + #ifndef DWORD + #define DWORD long int + #endif + + #ifndef WORD + #define WORD short int + #endif + + #ifndef __EXE386__ + #define __EXE386__ + + #pragma pack(1) /* Force byte alignment */ + + /*_________________________________________________________________* + | | + | | + | OS/2 .EXE FILE HEADER DEFINITION - 386 version 0:32 | + | | + |_________________________________________________________________| + * */ + + #define BITPERWORD 16 + #define BITPERBYTE 8 + #define OBJPAGELEN 4096 + #define E32MAGIC1 'L' /* New magic number "LX" */ + #define E32MAGIC2 'X' /* New magic number "LX" */ + #define E32MAGIC 0x584c /* New magic number "LX" */ + #define E32RESBYTES1 0 /* First bytes reserved */ + #define E32RESBYTES2 0 /* Second bytes reserved */ + #define E32RESBYTES3 20 /* Third bytes reserved */ + #define E32LEBO 0x00 /* Little Endian Byte Order */ + #define E32BEBO 0x01 /* Big Endian Byte Order */ + #define E32LEWO 0x00 /* Little Endian Word Order */ + #define E32BEWO 0x01 /* Big Endian Word Order */ + #define E32LEVEL 0L /* 32-bit EXE format level */ + #define E32CPU286 0x001 /* Intel 80286 or upwardly compatibile */ + #define E32CPU386 0x002 /* Intel 80386 or upwardly compatibile */ + #define E32CPU486 0x003 /* Intel 80486 or upwardly compatibile */ + + + + struct e32_exe /* New 32-bit .EXE header */ + { + unsigned char e32_magic[2]; /* Magic number E32_MAGIC */ + unsigned char e32_border; /* The byte ordering for the .EXE */ + unsigned char e32_worder; /* The word ordering for the .EXE */ + unsigned long e32_level; /* The EXE format level for now = 0 */ + unsigned short e32_cpu; /* The CPU type */ + unsigned short e32_os; /* The OS type */ + unsigned long e32_ver; /* Module version */ + unsigned long e32_mflags; /* Module flags */ + unsigned long e32_mpages; /* Module # pages */ + unsigned long e32_startobj; /* Object # for instruction pointer */ + unsigned long e32_eip; /* Extended instruction pointer */ + unsigned long e32_stackobj; /* Object # for stack pointer */ + unsigned long e32_esp; /* Extended stack pointer */ + unsigned long e32_pagesize; /* .EXE page size */ + unsigned long e32_pageshift; /* Page alignment shift in .EXE */ + unsigned long e32_fixupsize; /* Fixup section size */ + unsigned long e32_fixupsum; /* Fixup section checksum */ + unsigned long e32_ldrsize; /* Loader section size */ + unsigned long e32_ldrsum; /* Loader section checksum */ + unsigned long e32_objtab; /* Object table offset */ + unsigned long e32_objcnt; /* Number of objects in module */ + unsigned long e32_objmap; /* Object page map offset */ + unsigned long e32_itermap; /* Object iterated data map offset */ + unsigned long e32_rsrctab; /* Offset of Resource Table */ + unsigned long e32_rsrccnt; /* Number of resource entries */ + unsigned long e32_restab; /* Offset of resident name table */ + unsigned long e32_enttab; /* Offset of Entry Table */ + unsigned long e32_dirtab; /* Offset of Module Directive Table */ + unsigned long e32_dircnt; /* Number of module directives */ + unsigned long e32_fpagetab; /* Offset of Fixup Page Table */ + unsigned long e32_frectab; /* Offset of Fixup Record Table */ + unsigned long e32_impmod; /* Offset of Import Module Name Table */ + unsigned long e32_impmodcnt; /* Number of entries in Import Module Name Table */ + unsigned long e32_impproc; /* Offset of Import Procedure Name Table */ + unsigned long e32_pagesum; /* Offset of Per-Page Checksum Table */ + unsigned long e32_datapage; /* Offset of Enumerated Data Pages */ + unsigned long e32_preload; /* Number of preload pages */ + unsigned long e32_nrestab; /* Offset of Non-resident Names Table */ + unsigned long e32_cbnrestab; /* Size of Non-resident Name Table */ + unsigned long e32_nressum; /* Non-resident Name Table Checksum */ + unsigned long e32_autodata; /* Object # for automatic data object */ + unsigned long e32_debuginfo; /* Offset of the debugging information */ + unsigned long e32_debuglen; /* The length of the debugging info. in bytes */ + unsigned long e32_instpreload;/* Number of instance pages in preload section of .EXE file */ + unsigned long e32_instdemand; /* Number of instance pages in demand load section of .EXE file */ + unsigned long e32_heapsize; /* Size of heap - for 16-bit apps */ + unsigned long e32_stacksize; /* Size of stack */ + unsigned char e32_res3[E32RESBYTES3]; + /* Pad structure to 196 bytes */ + }; + + + + #define E32_MAGIC1(x) (x).e32_magic[0] + #define E32_MAGIC2(x) (x).e32_magic[1] + #define E32_BORDER(x) (x).e32_border + #define E32_WORDER(x) (x).e32_worder + #define E32_LEVEL(x) (x).e32_level + #define E32_CPU(x) (x).e32_cpu + #define E32_OS(x) (x).e32_os + #define E32_VER(x) (x).e32_ver + #define E32_MFLAGS(x) (x).e32_mflags + #define E32_MPAGES(x) (x).e32_mpages + #define E32_STARTOBJ(x) (x).e32_startobj + #define E32_EIP(x) (x).e32_eip + #define E32_STACKOBJ(x) (x).e32_stackobj + #define E32_ESP(x) (x).e32_esp + #define E32_PAGESIZE(x) (x).e32_pagesize + #define E32_PAGESHIFT(x) (x).e32_pageshift + #define E32_FIXUPSIZE(x) (x).e32_fixupsize + #define E32_FIXUPSUM(x) (x).e32_fixupsum + #define E32_LDRSIZE(x) (x).e32_ldrsize + #define E32_LDRSUM(x) (x).e32_ldrsum + #define E32_OBJTAB(x) (x).e32_objtab + #define E32_OBJCNT(x) (x).e32_objcnt + #define E32_OBJMAP(x) (x).e32_objmap + #define E32_ITERMAP(x) (x).e32_itermap + #define E32_RSRCTAB(x) (x).e32_rsrctab + #define E32_RSRCCNT(x) (x).e32_rsrccnt + #define E32_RESTAB(x) (x).e32_restab + #define E32_ENTTAB(x) (x).e32_enttab + #define E32_DIRTAB(x) (x).e32_dirtab + #define E32_DIRCNT(x) (x).e32_dircnt + #define E32_FPAGETAB(x) (x).e32_fpagetab + #define E32_FRECTAB(x) (x).e32_frectab + #define E32_IMPMOD(x) (x).e32_impmod + #define E32_IMPMODCNT(x) (x).e32_impmodcnt + #define E32_IMPPROC(x) (x).e32_impproc + #define E32_PAGESUM(x) (x).e32_pagesum + #define E32_DATAPAGE(x) (x).e32_datapage + #define E32_PRELOAD(x) (x).e32_preload + #define E32_NRESTAB(x) (x).e32_nrestab + #define E32_CBNRESTAB(x) (x).e32_cbnrestab + #define E32_NRESSUM(x) (x).e32_nressum + #define E32_AUTODATA(x) (x).e32_autodata + #define E32_DEBUGINFO(x) (x).e32_debuginfo + #define E32_DEBUGLEN(x) (x).e32_debuglen + #define E32_INSTPRELOAD(x) (x).e32_instpreload + #define E32_INSTDEMAND(x) (x).e32_instdemand + #define E32_HEAPSIZE(x) (x).e32_heapsize + #define E32_STACKSIZE(x) (x).e32_stacksize + + + + /* + * Format of E32_MFLAGS(x): + * + * Low word has the following format: + * + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no + * | | | | | | | | + * | | | | | | | +------- Per-Process Library Initialization + * | | | | | | +--------- SystemDLL (internal fixups discarded) + * | | | | | +----------- No Internal Fixups for Module in .EXE + * | | | | +------------- No External Fixups for Module in .EXE + * | | | +------------------- Incompatible with PM Windowing + * | | +--------------------- Compatible with PM Windowing + * | | Uses PM Windowing API + * | +-------------------------------- Module not Loadable + * +-------------------------------------- Library Module + */ + + + #define E32NOTP 0x8000L /* Library Module - used as NENOTP */ + #define E32NOLOAD 0x2000L /* Module not Loadable */ + #define E32PMAPI 0x0300L /* Uses PM Windowing API */ + #define E32PMW 0x0200L /* Compatible with PM Windowing */ + #define E32NOPMW 0x0100L /* Incompatible with PM Windowing */ + #define E32NOEXTFIX 0x0020L /* NO External Fixups in .EXE */ + #define E32NOINTFIX 0x0010L /* NO Internal Fixups in .EXE */ + #define E32SYSDLL 0x0008L /* System DLL, Internal Fixups discarded*/ + #define E32LIBINIT 0x0004L /* Per-Process Library Initialization */ + #define E32LIBTERM 0x40000000L /* Per-Process Library Termination */ + #define E32APPMASK 0x0300L /* Application Type Mask */ + + + /* + * Format of E32_MFLAGS(x): + * + * High word has the following format: + * + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no + * | | + * | +--- Protected memory library module + * +----- Device driver + */ + + #define E32PROTDLL 0x10000L /* Protected memory library module */ + #define E32DEVICE 0x20000L /* Device driver */ + #define E32MODEXE 0x00000L /* .EXE module */ + #define E32MODDLL 0x08000L /* .DLL module */ + #define E32MODPROTDLL 0x18000L /* Protected memory library module */ + #define E32MODPDEV 0x20000L /* Physical device driver */ + #define E32MODVDEV 0x28000L /* Virtual device driver */ + #define E32MODMASK 0x38000L /* Module type mask */ + + /* + * RELOCATION DEFINITIONS - RUN-TIME FIXUPS + */ + + typedef union _RELOC_OFS + { + unsigned short offset16; + unsigned long offset32; + } RELOC_OFS; /* 16-bit or 32-bit offset */ + + + /***ET+ r32_rlc - Relocation item */ + + struct r32_rlc /* Relocation item */ + { + unsigned char nr_stype; /* Source type - field shared with new_rlc */ + unsigned char nr_flags; /* Flag byte - field shared with new_rlc */ + short r32_soff; /* Source offset */ + unsigned short r32_objmod; /* Target object number or Module ordinal */ + + union targetid + { + RELOC_OFS intref; /* Internal fixup */ + + union extfixup + { + RELOC_OFS proc; /* Procedure name offset */ + unsigned long ord; /* Procedure odrinal */ + } extref; /* External fixup */ + + struct addfixup + { + unsigned short entry; /* Entry ordinal */ + RELOC_OFS addval; /* Value added to the address */ + } addfix; /* Additive fixup */ + } + r32_target; /* Target data */ + unsigned short r32_srccount; /* Number of chained fixup records */ + unsigned short r32_chain; /* Chain head */ + }; + + /* + * In 32-bit .EXE file run-time relocations are written as varying size + * records, so we need many size definitions. + */ + + #define RINTSIZE16 8 + #define RINTSIZE32 10 + #define RORDSIZE 8 + #define RNAMSIZE16 8 + #define RNAMSIZE32 10 + #define RADDSIZE16 10 + #define RADDSIZE32 12 + + #if FALSE + /* + * Access macros defined in NEWEXE.H !!! + */ + #define NR_STYPE(x) (x).nr_stype + #define NR_FLAGS(x) (x).nr_flags + #endif + + #define R32_SOFF(x) (x).r32_soff + #define R32_OBJNO(x) (x).r32_objmod + #define R32_MODORD(x) (x).r32_objmod + #define R32_OFFSET16(x) (x).r32_target.intref.offset16 + #define R32_OFFSET32(x) (x).r32_target.intref.offset32 + #define R32_PROCOFF16(x) (x).r32_target.extref.proc.offset16 + #define R32_PROCOFF32(x) (x).r32_target.extref.proc.offset32 + #define R32_PROCORD(x) (x).r32_target.extref.ord + #define R32_ENTRY(x) (x).r32_target.addfix.entry + #define R32_ADDVAL16(x) (x).r32_target.addfix.addval.offset16 + #define R32_ADDVAL32(x) (x).r32_target.addfix.addval.offset32 + #define R32_SRCCNT(x) (x).r32_srccount + #define R32_CHAIN(x) (x).r32_chain + + + + /* + * Format of NR_STYPE(x) + * + * 7 6 5 4 3 2 1 0 - bit no + * | | | | | | + * | | +-+-+-+--- Source type + * | +----------- Fixup to 16:16 alias + * +------------- List of source offset follows fixup record + */ + + #if FALSE + + /* DEFINED in newexe.h !!! */ + + #define NRSTYP 0x0f /* Source type mask */ + #define NRSBYT 0x00 /* lo byte (8-bits)*/ + #define NRSSEG 0x02 /* 16-bit segment (16-bits) */ + #define NRSPTR 0x03 /* 16:16 pointer (32-bits) */ + #define NRSOFF 0x05 /* 16-bit offset (16-bits) */ + #define NRPTR48 0x06 /* 16:32 pointer (48-bits) */ + #define NROFF32 0x07 /* 32-bit offset (32-bits) */ + #define NRSOFF32 0x08 /* 32-bit self-relative offset (32-bits) */ + #endif + + + #define NRSRCMASK 0x0f /* Source type mask */ + #define NRALIAS 0x10 /* Fixup to alias */ + #define NRCHAIN 0x20 /* List of source offset follows */ + /* fixup record, source offset field */ + /* in fixup record contains number */ + /* of elements in list */ + + /* + * Format of NR_FLAGS(x) and R32_FLAGS(x): + * + * 7 6 5 4 3 2 1 0 - bit no + * | | | | | | | + * | | | | | +-+--- Reference type + * | | | | +------- Additive fixup + * | | | +----------- 32-bit Target Offset Flag (1 - 32-bit; 0 - 16-bit) + * | | +------------- 32-bit Additive Flag (1 - 32-bit; 0 - 16-bit) + * | +--------------- 16-bit Object/Module ordinal (1 - 16-bit; 0 - 8-bit) + * +----------------- 8-bit import ordinal (1 - 8-bit; + * 0 - NR32BITOFF toggles + * between 16 and 32 bit + * ordinal) + */ + + #ifdef NEVER_INCLUDE_THE_FOLLWING + /* DEFINED in newexe.h !!! */ + #define NRRTYP 0x03 /* Reference type mask */ + #define NRRINT 0x00 /* Internal reference */ + #define NRRORD 0x01 /* Import by ordinal */ + #define NRRNAM 0x02 /* Import by name */ + #define NRADD 0x04 /* Additive fixup */ + #endif + + #define NRRENT 0x03 /* Internal entry table fixup */ + + #define NR32BITOFF 0x10 /* 32-bit Target Offset */ + #define NR32BITADD 0x20 /* 32-bit Additive fixup */ + #define NR16OBJMOD 0x40 /* 16-bit Object/Module ordinal */ + #define NR8BITORD 0x80 /* 8-bit import ordinal */ + /*end*/ + + /* + * Data structures for storing run-time fixups in linker virtual memory. + * + * Each object has a list of Object Page Directories which specify + * fixups for given page. Each page has its own hash table which is + * used to detect fixups to the same target. + */ + + #define PAGEPERDIR 62 + #define LG2DIR 7 + + + typedef struct _OBJPAGEDIR + { + DWORD next; /* Virtual pointer to next dir on list */ + WORD ht[PAGEPERDIR]; /* Pointers to individual hash tables */ + } + OBJPAGEDIR; + + /* + * OBJECT TABLE + */ + + /***ET+ o32_obj Object Table Entry */ + + struct o32_obj /* Flat .EXE object table entry */ + { + unsigned long o32_size; /* Object virtual size */ + unsigned long o32_base; /* Object base virtual address */ + unsigned long o32_flags; /* Attribute flags */ + unsigned long o32_pagemap; /* Object page map index */ + unsigned long o32_mapsize; /* Number of entries in object page map */ + unsigned long o32_reserved; /* Reserved */ + }; + + + #define O32_SIZE(x) (x).o32_size + #define O32_BASE(x) (x).o32_base + #define O32_FLAGS(x) (x).o32_flags + #define O32_PAGEMAP(x) (x).o32_pagemap + #define O32_MAPSIZE(x) (x).o32_mapsize + #define O32_RESERVED(x) (x).o32_reserved + + /* + * Format of O32_FLAGS(x) + * + * High word of dword flag field is not used for now. + * Low word has the following format: + * + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no + * | | | | | | | | | | | | | | | + * | | | | | | | | | | | | | | +--- Readable Object + * | | | | | | | | | | | | | +----- Writeable Object + * | | | | | | | | | | | | +------- Executable Object + * | | | | | | | | | | | +--------- Resource Object + * | | | | | | | | | | +----------- Object is Discardable + * | | | | | | | | | +------------- Object is Shared + * | | | | | | | | +--------------- Object has preload pages + * | | | | | | | +----------------- Object has invalid pages + * | | | | | | +------------------- Object is permanent and swappable + * | | | | | +--------------------- Object is permanent and resident + * | | | | +----------------------- Object is permanent and long lockable + * | | | +----------------------------- 16:16 alias required (80x86 specific) + * | | +-------------------------------- Big/Default bit setting (80x86 specific) + * | +----------------------------------- Object is conforming for code (80x86 specific) + * +-------------------------------------- Object I/O privilege level (80x86 specific) + * + */ + + #define OBJREAD 0x0001L /* Readable Object */ + #define OBJWRITE 0x0002L /* Writeable Object */ + #define OBJRSRC 0x0008L /* Resource Object */ + #define OBJINVALID 0x0080L /* Object has invalid pages */ + #define LNKNONPERM 0x0600L /* Object is nonpermanent - should be */ + #define OBJNONPERM 0x0000L /* zero in the .EXE but LINK386 uses 6 */ + #define OBJPERM 0x0100L /* Object is permanent and swappable */ + #define OBJRESIDENT 0x0200L /* Object is permanent and resident */ + #define OBJCONTIG 0x0300L /* Object is resident and contiguous */ + #define OBJDYNAMIC 0x0400L /* Object is permanent and long locable */ + #define OBJTYPEMASK 0x0700L /* Object type mask */ + #define OBJALIAS16 0x1000L /* 16:16 alias required (80x86 specific) */ + #define OBJBIGDEF 0x2000L /* Big/Default bit setting (80x86 specific) */ + #define OBJIOPL 0x8000L /* Object I/O privilege level (80x86 specific) */ + #if FOR_EXEHDR + /* + * Name these flags differently for EXEHDR.EXE - avoid conflicts with 286 version + */ + #define OBJDISCARD 0x0010L /* Object is Discardable */ + #define OBJSHARED 0x0020L /* Object is Shared */ + #define OBJPRELOAD 0x0040L /* Object has preload pages */ + #define OBJEXEC 0x0004L /* Executable Object */ + #define OBJCONFORM 0x4000L /* Object is conforming for code (80x86 specific) */ + #else + /* + * Life will be easier, if we keep the same names for the following flags: + */ + #ifndef NSDISCARD + #define NSDISCARD 0x0010L /* Object is Discardable */ + #endif + #ifndef NSMOVE + #define NSMOVE NSDISCARD /* Moveable object is for sure Discardable */ + #endif + #ifndef NSSHARED + #define NSSHARED 0x0020L /* Object is Shared */ + #endif + #ifndef NSPRELOAD + #define NSPRELOAD 0x0040L /* Object has preload pages */ + #endif + #ifndef NSEXRD + #define NSEXRD 0x0004L /* Executable Object */ + #endif + #ifndef NSCONFORM + #define NSCONFORM 0x4000L /* Object is conforming for code (80x86 specific) */ + #endif + #endif + /*end*/ + + /***ET+ o32_map - Object Page Map entry */ + + struct o32_map /* Object Page Table entry */ + { + unsigned long o32_pagedataoffset; /* file offset of page */ + unsigned short o32_pagesize; /* # bytes of page data */ + unsigned short o32_pageflags; /* Per-Page attributes */ + }; + + + #define GETPAGEIDX(x) ((x).o32_pagedataoffset) + + #define PUTPAGEIDX(x,i) ((x).o32_pagedataoffset = ((unsigned long)(i))) + + #define PUTPAGESIZ(x,i) ((x).o32_pagesize = ((unsigned int)(i))) + + #define GETPAGESIZ(x) ((x).o32_pagesize) + + #define PAGEFLAGS(x) (x).o32_pageflags + + + #define VALID 0x0000 /* Valid Physical Page in .EXE */ + #define ITERDATA 0x0001 /* Iterated Data Page */ + #define INVALID 0x0002 /* Invalid Page */ + #define ZEROED 0x0003 /* Zero Filled Page */ + #define RANGE 0x0004 /* Range of pages */ + #define ITERDATA2 0x0005 /* Iterated Data Page Type II */ + /*end*/ + + /* + * RESOURCE TABLE + */ + + /***ET+ rsrc32 - Resource Table Entry */ + + struct rsrc32 /* Resource Table Entry */ + { + unsigned short type; /* Resource type */ + unsigned short name; /* Resource name */ + unsigned long cb; /* Resource size */ + unsigned short obj; /* Object number */ + unsigned long offset; /* Offset within object */ + }; + /*end*/ + + + /* + * Iteration Record format for 'EXEPACK'ed pages. + */ + struct LX_Iter + { + unsigned short LX_nIter; /* number of iterations */ + unsigned short LX_nBytes; /* number of bytes */ + unsigned char LX_Iterdata; /* iterated data byte(s) */ + }; + + + /* + * ENTRY TABLE DEFINITIONS + */ + + /***ET+ b32_bundle - Entry Table */ + + struct b32_bundle + { + unsigned char b32_cnt; /* Number of entries in this bundle */ + unsigned char b32_type; /* Bundle type */ + unsigned short b32_obj; /* Object number */ + }; /* Follows entry types */ + + struct e32_entry + { + unsigned char e32_flags; /* Entry point flags */ + union entrykind + { + RELOC_OFS e32_offset; /* 16-bit/32-bit offset entry */ + struct callgate + { + unsigned short offset; /* Offset in segment */ + unsigned short callgate; /* Callgate selector */ + } + e32_callgate; /* 286 (16-bit) call gate */ + struct fwd + { + unsigned short modord; /* Module ordinal number */ + unsigned long value; /* Proc name offset or ordinal */ + } + e32_fwd; /* Forwarder */ + } + e32_variant; /* Entry variant */ + }; + + + + #define B32_CNT(x) (x).b32_cnt + #define B32_TYPE(x) (x).b32_type + #define B32_OBJ(x) (x).b32_obj + + #define E32_EFLAGS(x) (x).e32_flags + #define E32_OFFSET16(x) (x).e32_variant.e32_offset.offset16 + #define E32_OFFSET32(x) (x).e32_variant.e32_offset.offset32 + #define E32_GATEOFF(x) (x).e32_variant.e32_callgate.offset + #define E32_GATE(x) (x).e32_variant.e32_callgate.callgate + #define E32_MODORD(x) (x).e32_variant.e32_fwd.modord + #define E32_VALUE(x) (x).e32_variant.e32_fwd.value + + #define FIXENT16 3 + #define FIXENT32 5 + #define GATEENT16 5 + #define FWDENT 7 + + /* + * BUNDLE TYPES + */ + + #define EMPTY 0x00 /* Empty bundle */ + #define ENTRY16 0x01 /* 16-bit offset entry point */ + #define GATE16 0x02 /* 286 call gate (16-bit IOPL) */ + #define ENTRY32 0x03 /* 32-bit offset entry point */ + #define ENTRYFWD 0x04 /* Forwarder entry point */ + #define TYPEINFO 0x80 /* Typing information present flag */ + + + /* + * Format for E32_EFLAGS(x) + * + * 7 6 5 4 3 2 1 0 - bit no + * | | | | | | | | + * | | | | | | | +--- exported entry + * | | | | | | +----- uses shared data + * +-+-+-+-+-+------- parameter word count + */ + + #define E32EXPORT 0x01 /* Exported entry */ + #define E32SHARED 0x02 /* Uses shared data */ + #define E32PARAMS 0xf8 /* Parameter word count mask */ + + /* + * Flags for forwarders only: + */ + + #define FWD_ORDINAL 0x01 /* Imported by ordinal */ + + + #pragma pack() /* Restore default alignment */ + + /*end*/ + + #endif /* __EXE386__ */ + +#endif diff --git a/sal/osl/os2/helpers/dosh.h b/sal/osl/os2/helpers/dosh.h new file mode 100644 index 000000000000..fe51ee9bc488 --- /dev/null +++ b/sal/osl/os2/helpers/dosh.h @@ -0,0 +1,49 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* This file Copyright (C) 1997-2006 Ulrich M�ller, + * Dmitry A. Steklenev. + * This file is part of the "XWorkplace helpers" source package. + * + * 2009-06-15 published under LGPL3 with Ulrich M�ller permission. + * + */ + +#if __cplusplus +extern "C" { +#endif + +#ifndef DOSH_HEADER_INCLUDED + #define DOSH_HEADER_INCLUDED + + CHAR doshQueryBootDrive(VOID); + +#endif + +#if __cplusplus +} +#endif diff --git a/sal/osl/os2/helpers/except.h b/sal/osl/os2/helpers/except.h new file mode 100644 index 000000000000..af303a9827e3 --- /dev/null +++ b/sal/osl/os2/helpers/except.h @@ -0,0 +1,255 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* + *@@sourcefile except.h: + * header file for except.c. See remarks there. + * + * Note: Version numbering in this file relates to XWorkplace version + * numbering. + * + *@@include #define INCL_DOSEXCEPTIONS + *@@include #define INCL_DOSPROCESS + *@@include #include <os2.h> + *@@include #include <stdio.h> + *@@include #include <setjmp.h> + *@@include #include "helpers\except.h" + */ + +/* + * Copyright (C) 1999-2000 Ulrich M�ller. + * + * 2009-06-15 published under LGPL3 with Ulrich M�ller permission. + * + */ + +#if __cplusplus +extern "C" { +#endif + +#ifndef EXCEPT_HEADER_INCLUDED + #define EXCEPT_HEADER_INCLUDED + + #if defined __IBMCPP__ || defined __IBMC__ + #ifndef INCL_DOSEXCEPTIONS + #error except.h requires INCL_DOSEXCEPTIONS to be defined. + #endif + #ifndef INCL_DOSPROCESS + #error except.h requires INCL_DOSPROCESS to be defined. + #endif + + #ifndef __stdio_h + #error except.h requires stdio.h to be included. + #endif + #ifndef __setjmp_h + #error except.h requires setjmp.h to be included. + #endif + #endif + + /******************************************************************** + * + * Declarations + * + ********************************************************************/ + + // forward declaration + typedef struct _EXCEPTIONREGISTRATIONRECORD2 *PEXCEPTIONREGISTRATIONRECORD2; + + // "OnKill" function prototype for EXCEPTIONREGISTRATIONRECORD2 + // added V0.9.0 (99-10-22) [umoeller] + // removed V0.9.7 (2000-12-08) [umoeller] + // typedef VOID APIENTRY FNEXCONKILL(PEXCEPTIONREGISTRATIONRECORD2); + // typedef FNEXCONKILL *PFNEXCONKILL; + + /* + *@@ EXCEPTIONREGISTRATIONRECORD2: + * replacement EXCEPTIONREGISTRATIONRECORD + * struct for thread exception handling. + * + *@@changed V0.9.0 (99-10-22) [umoeller]: pfnOnKill added + *@@changed V0.9.0 (99-10-22) [umoeller]: renamed from REGREC2 + */ + + typedef struct _EXCEPTIONREGISTRATIONRECORD2 + { + PVOID pNext; // as in EXCEPTIONREGISTRATIONRECORD + PFN pfnHandler; // as in EXCEPTIONREGISTRATIONRECORD + jmp_buf jmpThread; // additional buffer for setjmp + EXCEPTIONREPORTRECORD err; // exception handlers copy the report rec here + PVOID pvUser; // user ptr + } EXCEPTIONREGISTRATIONRECORD2; + + /* + *@@ EXCEPTSTRUCT: + * structure used with TRY_xxx macros. + */ + + typedef struct _EXCEPTSTRUCT + { + EXCEPTIONREGISTRATIONRECORD2 RegRec2; + ULONG ulExcpt; // != NULL if exception caught + APIRET arc; // rc of DosSetExceptionHandler + } EXCEPTSTRUCT, *PEXCEPTSTRUCT; + + // function prototypes for exception hooks (V0.9.0) + + // "open traplog file" hook + typedef FILE* APIENTRY FNEXCOPENFILE(VOID); + typedef FNEXCOPENFILE *PFNEXCOPENFILE; + + // "exception" hook + typedef VOID APIENTRY FNEXCHOOK(FILE*, PTIB, ULONG); // V0.9.16 (2001-12-02) [pr] + typedef FNEXCHOOK *PFNEXCHOOK; + + // "error" hook + typedef VOID APIENTRY FNEXCHOOKERROR(const char *pcszFile, + ULONG ulLine, + const char *pcszFunction, + APIRET arc); + typedef FNEXCHOOKERROR *PFNEXCHOOKERROR; + + /******************************************************************** + * + * Prototypes + * + ********************************************************************/ + + VOID excExplainException(FILE *file, + PSZ pszHandlerName, + PEXCEPTIONREPORTRECORD pReportRec, + PCONTEXTRECORD pContextRec); + + VOID excRegisterHooks(PFNEXCOPENFILE pfnExcOpenFileNew, + PFNEXCHOOK pfnExcHookNew, + PFNEXCHOOKERROR pfnExcHookError, + BOOL fBeepOnExceptionNew); + + ULONG _System excHandlerLoud(PEXCEPTIONREPORTRECORD pReportRec, + PEXCEPTIONREGISTRATIONRECORD2 pRegRec2, + PCONTEXTRECORD pContextRec, + PVOID pv); + + ULONG _System excHandlerQuiet(PEXCEPTIONREPORTRECORD pReportRec, + PEXCEPTIONREGISTRATIONRECORD2 pRegRec2, + PCONTEXTRECORD pContextRec, + PVOID pv); + + extern PFNEXCHOOKERROR G_pfnExcHookError; + + extern ULONG G_ulExplainExceptionRunning; + + /******************************************************************** + * + * Macros + * + ********************************************************************/ + + /* See except.c for explanations how to use these. */ + + #ifdef __NO_EXCEPTION_HANDLERS__ + // exception handlers can completely be disabled + #define TRY_LOUD(excptstruct) + #else + #ifdef __NO_LOUD_EXCEPTION_HANDLERS__ + #define TRY_LOUD(e) TRY_QUIET(e) + #else // __NO_LOUD_EXCEPTION_HANDLERS__ + #define TRY_LOUD(excptstruct) \ + { \ + EXCEPTSTRUCT excptstruct = {0}; \ + excptstruct.RegRec2.pfnHandler = (PFN)excHandlerLoud; \ + excptstruct.arc = DosSetExceptionHandler( \ + (PEXCEPTIONREGISTRATIONRECORD)&(excptstruct.RegRec2)); \ + if (excptstruct.arc) \ + if (G_pfnExcHookError) \ + G_pfnExcHookError(__FILE__, __LINE__, __FUNCTION__, excptstruct.arc); \ + else \ + DosBeep(1000, 1000); \ + excptstruct.ulExcpt = setjmp(excptstruct.RegRec2.jmpThread); \ + if (excptstruct.ulExcpt == 0) \ + { + + #endif // __NO_LOUD_EXCEPTION_HANDLERS__ + #endif + + #ifdef __NO_EXCEPTION_HANDLERS__ + // exception handlers can completely be disabled + #define TRY_QUIET(excptstruct) + #else + #define TRY_QUIET(excptstruct) \ + { \ + EXCEPTSTRUCT excptstruct = {0}; \ + excptstruct.RegRec2.pfnHandler = (PFN)excHandlerQuiet; \ + excptstruct.arc = DosSetExceptionHandler( \ + (PEXCEPTIONREGISTRATIONRECORD)&(excptstruct.RegRec2)); \ + if (excptstruct.arc) \ + if (G_pfnExcHookError) \ + G_pfnExcHookError(__FILE__, __LINE__, __FUNCTION__, excptstruct.arc); \ + else \ + DosBeep(1000, 1000); \ + excptstruct.ulExcpt = setjmp(excptstruct.RegRec2.jmpThread); \ + if (excptstruct.ulExcpt == 0) \ + { + + #endif + + #ifdef __NO_EXCEPTION_HANDLERS__ + // exception handlers can completely be disabled + #define CATCH(excptstruct) if (FALSE) { + #else + #define CATCH(excptstruct) \ + DosUnsetExceptionHandler( \ + (PEXCEPTIONREGISTRATIONRECORD)&(excptstruct.RegRec2)); \ + } /* end of TRY block */ \ + else \ + { /* exception occured: */ \ + DosUnsetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&(excptstruct.RegRec2)); + #endif + + #ifdef __NO_EXCEPTION_HANDLERS__ + // exception handlers can completely be disabled + #define END_CATCH() } + #else + #define END_CATCH() \ + } /* end of exception-occured block */ \ + } + #endif + + /* + * CRASH: + * this macro is helpful for testing + * the exception handlers. + * This is not for general use. ;-) + */ + + #define CRASH {PSZ p = NULL; *p = 'a'; } + +#endif // EXCEPT_HEADER_INCLUDED + +#if __cplusplus +} +#endif + diff --git a/sal/osl/os2/helpers/setup.h b/sal/osl/os2/helpers/setup.h new file mode 100644 index 000000000000..b9c6e50f0111 --- /dev/null +++ b/sal/osl/os2/helpers/setup.h @@ -0,0 +1,147 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* + * setup.h: + * sample master include file which gets included + * from all helpers *.c sources. + */ + +#ifndef SETUP_HEADER_INCLUDED + #define SETUP_HEADER_INCLUDED + + // XWPEXPORT defines the standard linkage for the + // XWorkplace helpers. + #ifdef __EMX__ + #define XWPENTRY + #elif defined (__IBMCPP__) || defined (__IBMC__) + #define XWPENTRY _Optlink + #endif + + /************************************************************* + * * + * Additional stuff for EMX * + * * + *************************************************************/ + + #ifdef __EMX__ + // EMX doesn't have all these 16-bit typedefs; + // added (99-10-22) [umoeller] + #define APIENTRY16 _Far16 _Pascal + #define PASCAL16 _Far16 _Pascal + #define CDECL16 _Far16 _Cdecl + + typedef unsigned short APIRET16; + typedef unsigned long APIRET32; + +#if 0 +//YD do not use with gcc 3.3.5 + #define _System + #define APIENTRY + // with VAC++, this defines _System linkage, which + // EMX doesn't have, or does it?!? +#endif // 0 + + #endif + + // the following is a VAC++-specific macro, which doesn't exist + // with EMX, so we need to implement this... this was one of + // the "undefined symbols" we got (99-10-23) [umoeller] + // changed this to prefix underscore, because the STL apparently + // redefines this V0.9.3 (2000-05-15) [umoeller] + #define _min(a,b) ( ((a) > (b)) ? b : a ) + #define _max(a,b) ( ((a) > (b)) ? a : b ) + + // Uncomment the following if you have trouble with the + // exception handlers in helpers\except.c; WarpIN will + // then install _no_ additional exception handlers at all + // (include\helpers\except.h reacts to these defines). + // I'm not sure if the handlers work well with EMX. + + #ifdef __EMX__00 + #define __NO_EXCEPTION_HANDLERS__ + #endif + + /************************************************************* + * * + * Additional stuff for VAC++ 3.0 * + * * + *************************************************************/ + + // all this added V0.9.2 (2000-03-10) [umoeller] + #if ( defined ( __IBMCPP__ ) && ( __IBMCPP__ < 400 ) ) + typedef int bool; + #define true 1 + #define false 0 + #define _BooleanConst // needed for some VAC headers, which define bool also + #endif + + #ifndef __stdlib_h // <stdlib.h> + #include <stdlib.h> + #endif + #ifndef __string_h // <string.h> + #include <string.h> + #endif + + /************************************************************* + * * + * Debugging * + * * + *************************************************************/ + + // All the following redone (99-10-23) [umoeller]: + // __DEBUG__ is defined as a macro on the compiler + // command line by the makefiles if DEBUG was enabled + // in \setup.in + #ifdef __DEBUG__ + + // with debug code, disable the exception handlers + #define __NO_EXCEPTION_HANDLERS__ + + // If the following is commented out, no PMPRINTF will be + // used at all. WarpIN uses Dennis Bareis' PMPRINTF + // package to do this. + + // NOTE: We cannot use PmPrintf with EMX, + // because pmprintf.lib imports the VAC++ runtimes. + // That's the strange errors I was reporting yesterday. + #ifndef __EMX__ + #ifdef OS2_INCLUDED + #define _PMPRINTF_ + #include "helpers/pmprintf.h" + #endif + #endif + #endif + + #ifndef _PMPRINTF_ + // not defined: define empty macro so we don't + // get compiler errors + #define _Pmpf(x) + #endif + +#endif + diff --git a/sal/osl/os2/interlck.c b/sal/osl/os2/interlck.c new file mode 100644 index 000000000000..589005f215b9 --- /dev/null +++ b/sal/osl/os2/interlck.c @@ -0,0 +1,51 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <386/builtin.h> + +#include "system.h" + +#include <osl/interlck.h> +#include <osl/diagnose.h> + +/*****************************************************************************/ +/* osl_incrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount) +{ + return __atomic_increment_s32( pCount); +} + +/*****************************************************************************/ +/* osl_decrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount) +{ + return __atomic_decrement_s32( pCount); +} + + diff --git a/sal/osl/os2/libutil.c b/sal/osl/os2/libutil.c new file mode 100644 index 000000000000..e0f94a8b3235 --- /dev/null +++ b/sal/osl/os2/libutil.c @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if 0 // YD + +#include <windows.h> + +static BOOL g_bInit = FALSE; +static DWORD g_dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + +DWORD GetPlatformId() +{ + + if (!g_bInit) + { + OSVERSIONINFO aInfo; + + aInfo.dwOSVersionInfoSize = sizeof(aInfo); + if (GetVersionEx(&aInfo)) + g_dwPlatformId = aInfo.dwPlatformId; + + g_bInit = TRUE; + } + + return g_dwPlatformId; +} + +#endif // 0 diff --git a/sal/osl/os2/makefile.mk b/sal/osl/os2/makefile.mk new file mode 100644 index 000000000000..c9bfd3f96771 --- /dev/null +++ b/sal/osl/os2/makefile.mk @@ -0,0 +1,118 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=sal +TARGET=cpposl +USE_LDUMP2=TRUE + +PROJECTPCH4DLL=TRUE +PROJECTPCH=cont_pch +PROJECTPCHSOURCE=cont_pch + +MULTITHREAD_OBJ=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# Uncomment the following line if you want to compile with -Wall +# it disables lots of unnecessary warnings comming from the Win32 +# header files (disabling warnings via command line only works with +# MSVC >= 7.x) +# +# CFLAGS+=/wd4668 /wd4711 /wd4201 /wd4710 /wd4619 /wd4514 /wd4820 + +# --- Files -------------------------------------------------------- + +.IF "$(header)" == "" + +SLOFILES= $(SLO)$/conditn.obj \ + $(SLO)$/diagnose.obj \ + $(SLO)$/dllentry.obj \ + $(SLO)$/semaphor.obj \ + $(SLO)$/interlck.obj \ + $(SLO)$/nlsupport.obj\ + $(SLO)$/mutex.obj \ + $(SLO)$/module.obj \ + $(SLO)$/process.obj \ + $(SLO)$/time.obj \ + $(SLO)$/signal.obj \ + $(SLO)$/pipe.obj \ + $(SLO)$/util.obj \ + $(SLO)$/socket.obj \ + $(SLO)$/thread.obj \ + $(SLO)$/security.obj \ + $(SLO)$/profile.obj \ + $(SLO)$/tempfile.obj \ + $(SLO)$/process_impl.obj\ + $(SLO)$/uunxapi.obj\ + $(SLO)$/file.obj \ + $(SLO)$/file_url.obj \ + $(SLO)$/file_error_transl.obj \ + $(SLO)$/file_path_helper.obj \ + $(SLO)$/debug.obj \ + $(SLO)$/except.obj \ + $(SLO)$/salinit.obj + +OBJFILES= $(OBJ)$/conditn.obj \ + $(OBJ)$/diagnose.obj \ + $(OBJ)$/libutil.obj \ + $(OBJ)$/semaphor.obj \ + $(OBJ)$/interlck.obj \ + $(OBJ)$/nlsupport.obj\ + $(OBJ)$/mutex.obj \ + $(OBJ)$/module.obj \ + $(OBJ)$/process.obj \ + $(OBJ)$/time.obj \ + $(OBJ)$/signal.obj \ + $(OBJ)$/pipe.obj \ + $(OBJ)$/util.obj \ + $(OBJ)$/socket.obj \ + $(OBJ)$/thread.obj \ + $(OBJ)$/security.obj \ + $(OBJ)$/profile.obj \ + $(OBJ)$/tempfile.obj \ + $(OBJ)$/process_impl.obj\ + $(OBJ)$/uunxapi.obj\ + $(OBJ)$/file.obj \ + $(OBJ)$/file_url.obj \ + $(OBJ)$/file_error_transl.obj \ + $(OBJ)$/file_path_helper.obj \ + $(OBJ)$/debug.obj \ + $(OBJ)$/except.obj \ + $(SLO)$/salinit.obj + +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + + + diff --git a/sal/osl/os2/module.c b/sal/osl/os2/module.c new file mode 100644 index 000000000000..421b78195d83 --- /dev/null +++ b/sal/osl/os2/module.c @@ -0,0 +1,281 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/module.h> +#include <osl/diagnose.h> +#include <osl/file.h> +#include <osl/thread.h> + +#include <stdlib.h> + +int UnicodeToText(char *, size_t, const sal_Unicode *, sal_Int32); + +// static data for holding SAL dll module and full path +static HMODULE hModSal; +static char szSalDir[ _MAX_PATH]; +static char szSalDrive[ _MAX_PATH]; + +/*****************************************************************************/ +/* osl_loadModule */ +/*****************************************************************************/ + +ULONG APIENTRY _DosLoadModule (PSZ pszObject, ULONG uObjectLen, PCSZ pszModule, + PHMODULE phmod) +{ + APIRET rc; + rc = DosLoadModule( pszObject, uObjectLen, pszModule, phmod); + // YD 22/05/06 issue again if first call fails (why?) + if (rc == ERROR_INVALID_PARAMETER) + rc = DosLoadModule( pszObject, uObjectLen, pszModule, phmod); + return rc; +} + +oslModule SAL_CALL osl_loadModule(rtl_uString *ustrModuleName, sal_Int32 nRtldMode) +{ + HMODULE hModule; + BYTE szErrorMessage[256]; + APIRET rc; + oslModule pModule=0; + rtl_uString* ustrTmp = NULL; + + OSL_ENSURE(ustrModuleName,"osl_loadModule : string is not valid"); + + /* ensure ustrTmp hold valid string */ + if( osl_File_E_None != osl_getSystemPathFromFileURL( ustrModuleName, &ustrTmp ) ) + rtl_uString_assign( &ustrTmp, ustrModuleName ); + + if( ustrTmp ) + { + char buffer[PATH_MAX]; + + if( UnicodeToText( buffer, PATH_MAX, ustrTmp->buffer, ustrTmp->length ) ) + { + char drive[_MAX_DRIVE], dir[_MAX_DIR]; + char fname[_MAX_FNAME], ext[_MAX_EXT]; + char* dot; + // 21/02/2006 YD dll names must be 8.3: since .uno.dll files + // have hardcoded names, I'm truncating names here and also in + // the build system + _splitpath (buffer, drive, dir, fname, ext); + if (strlen(fname)>8) + fname[8] = 0; // truncate to 8.3 + dot = strchr( fname, '.'); + if (dot) + *dot = '\0'; // truncate on dot + // if drive is not specified, remove starting \ from dir name + // so dll is loaded from LIBPATH + if (drive[0] == 0 && dir[0] == '\\' && dir[1] == '\\') { + while( dir[0] == '\\') + strcpy( dir, dir+1); + } + _makepath( buffer, drive, dir, fname, ext); + + rc = _DosLoadModule( szErrorMessage, sizeof( szErrorMessage), (PCSZ)buffer, &hModule); + if (rc == NO_ERROR ) + pModule = (oslModule)hModule; + else + { + if (rc == NO_ERROR ) + pModule = (oslModule)hModule; + else + { + sal_Char szError[ PATH_MAX*2 ]; + sprintf( szError, "Module: %s; rc: %d;\nReason: %s;\n" + "Please contact technical support and report above informations.\n\n", + buffer, rc, szErrorMessage ); +#if OSL_DEBUG_LEVEL>0 + fprintf( stderr, szError); +#endif + //OSL_TRACE(szError); +#ifndef OSL_DEBUG_LEVEL + WinMessageBox(HWND_DESKTOP,HWND_DESKTOP, + szError, "Critical error: DosLoadModule failed", + 0, MB_ERROR | MB_OK | MB_MOVEABLE); +#endif + } + } + } + } + + rtl_uString_release( ustrTmp ); + + return pModule; +} + +/*****************************************************************************/ +/* osl_getModuleHandle */ +/*****************************************************************************/ + +sal_Bool SAL_CALL +osl_getModuleHandle(rtl_uString *pModuleName, oslModule *pResult) +{ + HMODULE hmod; + APIRET rc; + rc = DosQueryModuleHandle(pModuleName->buffer, &hmod); + if( rc == NO_ERROR) + { + *pResult = (oslModule) hmod; + return sal_True; + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_unloadModule */ +/*****************************************************************************/ +void SAL_CALL osl_unloadModule(oslModule Module) +{ +#if OSL_DEBUG_LEVEL>0 + if (!Module) + fprintf( stderr, "osl_unloadModule NULL HANDLE.\n"); +#endif + + DosFreeModule((HMODULE)Module); +} + +/*****************************************************************************/ +/* osl_getSymbol */ +/*****************************************************************************/ +void* SAL_CALL +osl_getSymbol(oslModule Module, rtl_uString* pSymbolName) +{ + return (void *) osl_getFunctionSymbol(Module, pSymbolName); +} + +/*****************************************************************************/ +/* osl_getFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL osl_getFunctionSymbol( oslModule Module, rtl_uString *strSymbolName ) +{ + rtl_String *symbolName = NULL; + oslGenericFunction address; + + OSL_ASSERT(Module); + OSL_ASSERT(strSymbolName); + + rtl_uString2String( + &symbolName, + strSymbolName->buffer, + strSymbolName->length, + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS + ); + + address=osl_getAsciiFunctionSymbol(Module, rtl_string_getStr(symbolName)); + rtl_string_release(symbolName); + + return address; +} + +/*****************************************************************************/ +/* osl_getAsciiFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL +osl_getAsciiFunctionSymbol( oslModule Module, const sal_Char *pSymbol ) +{ + PFN pFunction; + APIRET rc; + void* pHandle=0; + + OSL_ENSURE(Module,"osl_getSymbol : module handle is not valid"); + OSL_ENSURE(Module,"osl_getSymbol : ustrSymbolName"); + + if ( Module!= 0 && pSymbol != 0 ) + { + + rc = DosQueryProcAddr( (HMODULE) Module, 0, (PCSZ)pSymbol, &pFunction ); + if( rc == NO_ERROR ) + { + pHandle = (void*)pFunction; + } + else + { + // YD try again adding the '_' prefix + char _pszSymbolName[255]; + strcpy( _pszSymbolName, "_"); + strcat( _pszSymbolName, pSymbol); + rc = DosQueryProcAddr( (HMODULE) Module, 0, (PCSZ)_pszSymbolName, &pFunction ); + if( rc == NO_ERROR ) + pHandle = (void*)pFunction; + } + + } + + return pHandle; +} + +/*****************************************************************************/ +/* osl_getModuleURLFromAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromAddress(void * addr, rtl_uString ** ppLibraryUrl) +{ + //APIRET APIENTRY DosQueryModFromEIP (HMODULE *phMod, ULONG *pObjNum, + // ULONG BuffLen, PCHAR pBuff, ULONG *pOffset, ULONG Address) + HMODULE hMod; + ULONG ObjNum; + CHAR Buff[2*_MAX_PATH]; + ULONG Offset; + APIRET rc; + + // get module handle (and name) + rc = DosQueryModFromEIP( &hMod, &ObjNum, sizeof( Buff), Buff, &Offset, (ULONG)addr); + if (rc) + return sal_False; + + // get module full path + rc = DosQueryModuleName( hMod, sizeof( Buff), Buff); + if (rc) + return sal_False; + +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE("module.c::osl_getModuleURLFromAddress - %s\n", Buff); +#endif + + // convert to URL + rtl_uString *ustrSysPath = NULL; + rtl_string2UString( &ustrSysPath, Buff, strlen(Buff), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(ustrSysPath != NULL); + osl_getFileURLFromSystemPath( ustrSysPath, ppLibraryUrl ); + rtl_uString_release( ustrSysPath ); + + return sal_True; +} + +/*****************************************************************************/ +/* osl_getModuleURLFromFunctionAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress( oslGenericFunction addr, rtl_uString ** ppLibraryUrl ) +{ + return osl_getModuleURLFromAddress( ( void * )addr, ppLibraryUrl ); +} + +/*****************************************************************************/ + diff --git a/sal/osl/os2/mutex.c b/sal/osl/os2/mutex.c new file mode 100644 index 000000000000..e86b3f965608 --- /dev/null +++ b/sal/osl/os2/mutex.c @@ -0,0 +1,167 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <sys/fmutex.h> + +#include "system.h" + +#include <osl/mutex.h> +#include <osl/diagnose.h> + +/* + Implementation notes: + The void* hidden by oslMutex points to an OS/2 mutex semaphore. +*/ +typedef struct _oslMutexImpl { + HMTX m_Mutex; + int m_Locks; + ULONG m_Owner; + ULONG m_Requests; +} oslMutexImpl; + +// static mutex to control access to private members of oslMutexImpl +static HMTX MutexLock = 0; + +/*****************************************************************************/ +/* osl_createMutex */ +/*****************************************************************************/ +oslMutex SAL_CALL osl_createMutex() +{ + oslMutexImpl *pMutexImpl; + HMTX hMutex; + APIRET rc; + + pMutexImpl= (oslMutexImpl*)calloc(sizeof(oslMutexImpl), 1); + OSL_ASSERT(pMutexImpl); /* alloc successful? */ + + /* create semaphore */ + rc = DosCreateMutexSem( NULL, &pMutexImpl->m_Mutex, 0, FALSE ); + if( rc != 0 ) + { + free(pMutexImpl); + return NULL; + } + + // create static mutex for private members + if (MutexLock == 0) + DosCreateMutexSem( NULL, &MutexLock, 0, FALSE ); + + return (oslMutex)pMutexImpl; +} + +/*****************************************************************************/ +/* osl_destroyMutex */ +/*****************************************************************************/ +void SAL_CALL osl_destroyMutex(oslMutex Mutex) +{ + oslMutexImpl *pMutexImpl = (oslMutexImpl *)Mutex; + if (pMutexImpl) + { + DosCloseMutexSem( pMutexImpl->m_Mutex); + free(pMutexImpl); + } +} + +/*****************************************************************************/ +/* osl_acquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireMutex(oslMutex Mutex) +{ + oslMutexImpl *pMutexImpl = (oslMutexImpl *)Mutex; + APIRET rc = 0; + OSL_ASSERT(Mutex); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + pMutexImpl->m_Requests++; + DosReleaseMutexSem( MutexLock); + + rc = DosRequestMutexSem( pMutexImpl->m_Mutex, SEM_INDEFINITE_WAIT ); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + pMutexImpl->m_Requests--; + if (pMutexImpl->m_Locks++ == 0) + pMutexImpl->m_Owner = _gettid(); + DosReleaseMutexSem( MutexLock); + + return( rc == 0 ); +} + +/*****************************************************************************/ +/* osl_tryToAcquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireMutex(oslMutex Mutex) +{ + sal_Bool ret = sal_False; + oslMutexImpl *pMutexImpl = (oslMutexImpl *)Mutex; + OSL_ASSERT(Mutex); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + + if ( ((pMutexImpl->m_Requests == 0) && (pMutexImpl->m_Locks == 0)) || + (pMutexImpl->m_Owner == _gettid()) ) + ret = osl_acquireMutex(Mutex); + + DosReleaseMutexSem( MutexLock); + + return ret; +} + +/*****************************************************************************/ +/* osl_releaseMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseMutex(oslMutex Mutex) +{ + oslMutexImpl *pMutexImpl = (oslMutexImpl *)Mutex; + APIRET rc; + OSL_ASSERT(Mutex); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + + if (--(pMutexImpl->m_Locks) == 0) + pMutexImpl->m_Owner = 0; + + DosReleaseMutexSem( MutexLock); + + rc = DosReleaseMutexSem( pMutexImpl->m_Mutex); + + return sal_True; +} + + + +/*****************************************************************************/ +/* osl_getGlobalMutex */ +/*****************************************************************************/ + +oslMutex g_Mutex = NULL; + +oslMutex * SAL_CALL osl_getGlobalMutex(void) +{ + if (g_Mutex == NULL) + g_Mutex = osl_createMutex(); + return &g_Mutex; +} diff --git a/sal/osl/os2/nlsupport.c b/sal/osl/os2/nlsupport.c new file mode 100644 index 000000000000..ab00443e57d7 --- /dev/null +++ b/sal/osl/os2/nlsupport.c @@ -0,0 +1,445 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define INCL_WIN +#include "svpm.h" + +#include <osl/nlsupport.h> +#include <osl/diagnose.h> +#include <osl/process.h> +#include <rtl/memory.h> + +#include <string.h> + +/***************************************************************************** + typedefs + *****************************************************************************/ + + +typedef struct { + const char *key; + const rtl_TextEncoding value; +} _pair; + + +/***************************************************************************** + compare function for binary search + *****************************************************************************/ + +static int +_pair_compare (const char *key, const _pair *pair) +{ + int result = rtl_str_compareIgnoreAsciiCase( key, pair->key ); + return result; +} + +/***************************************************************************** + binary search on encoding tables + *****************************************************************************/ + +static const _pair* +_pair_search (const char *key, const _pair *base, unsigned int member ) +{ + unsigned int lower = 0; + unsigned int upper = member; + unsigned int current; + int comparison; + + /* check for validity of input */ + if ( (key == NULL) || (base == NULL) || (member == 0) ) + return NULL; + + /* binary search */ + while ( lower < upper ) + { + current = (lower + upper) / 2; + comparison = _pair_compare( key, base + current ); + if (comparison < 0) + upper = current; + else if (comparison > 0) + lower = current + 1; + else + return base + current; + } + + return NULL; +} + + +/***************************************************************************** + convert rtl_Locale to locale string + *****************************************************************************/ + +static char * _compose_locale( rtl_Locale * pLocale, char * buffer, size_t n ) +{ + /* check if a valid locale is specified */ + if( pLocale && pLocale->Language && (pLocale->Language->length == 2) ) + { + size_t offset = 0; + + /* convert language code to ascii */ + { + rtl_String *pLanguage = NULL; + + rtl_uString2String( &pLanguage, + pLocale->Language->buffer, pLocale->Language->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( pLanguage->length < n ) + { + strcpy( buffer, pLanguage->buffer ); + offset = pLanguage->length; + } + + rtl_string_release( pLanguage ); + } + + /* convert country code to ascii */ + if( pLocale->Country && (pLocale->Country->length == 2) ) + { + rtl_String *pCountry = NULL; + + rtl_uString2String( &pCountry, + pLocale->Country->buffer, pLocale->Country->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( offset + pCountry->length + 1 < n ) + { + strcpy( buffer + offset++, "_" ); + strcpy( buffer + offset, pCountry->buffer ); + offset += pCountry->length; + } + + rtl_string_release( pCountry ); + } + + /* convert variant to ascii - check if there is enough space for the variant string */ + if( pLocale->Variant && pLocale->Variant->length && + ( pLocale->Variant->length < n - 6 ) ) + { + rtl_String *pVariant = NULL; + + rtl_uString2String( &pVariant, + pLocale->Variant->buffer, pLocale->Variant->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( offset + pVariant->length + 1 < n ) + { + strcpy( buffer + offset, pVariant->buffer ); + offset += pVariant->length; + } + + rtl_string_release( pVariant ); + } + + return buffer; + } + + return NULL; +} + +/***************************************************************************** + convert locale string to rtl_Locale + *****************************************************************************/ + +static rtl_Locale * _parse_locale( const char * locale ) +{ + static sal_Unicode c_locale[2] = { (sal_Unicode) 'C', 0 }; + + /* check if locale contains a valid string */ + if( locale ) + { + size_t len = strlen( locale ); + + if( len >= 2 ) + { + rtl_uString * pLanguage = NULL; + rtl_uString * pCountry = NULL; + rtl_uString * pVariant = NULL; + + size_t offset = 2; + + /* convert language code to unicode */ + rtl_string2UString( &pLanguage, locale, 2, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pLanguage != NULL); + + /* convert country code to unicode */ + if( len >= 5 && '_' == locale[2] ) + { + rtl_string2UString( &pCountry, locale + 3, 2, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pCountry != NULL); + offset = 5; + } + + /* convert variant code to unicode - do not rely on "." as delimiter */ + if( len > offset ) { + rtl_string2UString( &pVariant, locale + offset, len - offset, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pVariant != NULL); + } + + rtl_Locale * ret = rtl_locale_register( pLanguage->buffer, pCountry ? pCountry->buffer : c_locale + 1, pVariant ? pVariant->buffer : c_locale + 1 ); + + if (pVariant) rtl_uString_release(pVariant); + if (pCountry) rtl_uString_release(pCountry); + if (pLanguage) rtl_uString_release(pLanguage); + + return ret; + } + else + return rtl_locale_register( c_locale, c_locale + 1, c_locale + 1 ); + } + + return NULL; +} + +/* + * This implementation of osl_getTextEncodingFromLocale maps + * from the ISO language codes. + */ + +const _pair _full_locale_list[] = { + { "ja_JP.eucJP", RTL_TEXTENCODING_EUC_JP }, + { "ja_JP.EUC", RTL_TEXTENCODING_EUC_JP }, + { "ko_KR.EUC", RTL_TEXTENCODING_EUC_KR }, + { "zh_CN.EUC", RTL_TEXTENCODING_EUC_CN }, + { "zh_TW.EUC", RTL_TEXTENCODING_EUC_TW } +}; + +const _pair _locale_extension_list[] = { + { "big5", RTL_TEXTENCODING_BIG5 }, + { "big5hk", RTL_TEXTENCODING_BIG5_HKSCS }, + { "gb18030", RTL_TEXTENCODING_GB_18030 }, + { "euc", RTL_TEXTENCODING_EUC_JP }, + { "iso8859-1", RTL_TEXTENCODING_ISO_8859_1 }, + { "iso8859-10", RTL_TEXTENCODING_ISO_8859_10 }, + { "iso8859-13", RTL_TEXTENCODING_ISO_8859_13 }, + { "iso8859-14", RTL_TEXTENCODING_ISO_8859_14 }, + { "iso8859-15", RTL_TEXTENCODING_ISO_8859_15 }, + { "iso8859-2", RTL_TEXTENCODING_ISO_8859_2 }, + { "iso8859-3", RTL_TEXTENCODING_ISO_8859_3 }, + { "iso8859-4", RTL_TEXTENCODING_ISO_8859_4 }, + { "iso8859-5", RTL_TEXTENCODING_ISO_8859_5 }, + { "iso8859-6", RTL_TEXTENCODING_ISO_8859_6 }, + { "iso8859-7", RTL_TEXTENCODING_ISO_8859_7 }, + { "iso8859-8", RTL_TEXTENCODING_ISO_8859_8 }, + { "iso8859-9", RTL_TEXTENCODING_ISO_8859_9 }, + { "koi8-r", RTL_TEXTENCODING_KOI8_R }, + { "koi8-u", RTL_TEXTENCODING_KOI8_U }, + { "pck", RTL_TEXTENCODING_MS_932 }, +#if (0) + { "sun_eu_greek", RTL_TEXTENCODING_DONTKNOW }, +#endif + { "utf-16", RTL_TEXTENCODING_UNICODE }, + { "utf-7", RTL_TEXTENCODING_UTF7 }, + { "utf-8", RTL_TEXTENCODING_UTF8 } +}; + +const _pair _iso_language_list[] = { + { "af", RTL_TEXTENCODING_ISO_8859_1 }, + { "ar", RTL_TEXTENCODING_ISO_8859_6 }, + { "az", RTL_TEXTENCODING_ISO_8859_9 }, + { "be", RTL_TEXTENCODING_ISO_8859_5 }, + { "bg", RTL_TEXTENCODING_ISO_8859_5 }, + { "ca", RTL_TEXTENCODING_ISO_8859_1 }, + { "cs", RTL_TEXTENCODING_ISO_8859_2 }, + { "da", RTL_TEXTENCODING_ISO_8859_1 }, + { "de", RTL_TEXTENCODING_ISO_8859_1 }, + { "el", RTL_TEXTENCODING_ISO_8859_7 }, + { "en", RTL_TEXTENCODING_ISO_8859_1 }, + { "es", RTL_TEXTENCODING_ISO_8859_1 }, + { "et", RTL_TEXTENCODING_ISO_8859_4 }, + { "eu", RTL_TEXTENCODING_ISO_8859_1 }, + { "fa", RTL_TEXTENCODING_ISO_8859_6 }, + { "fi", RTL_TEXTENCODING_ISO_8859_1 }, + { "fo", RTL_TEXTENCODING_ISO_8859_1 }, + { "fr", RTL_TEXTENCODING_ISO_8859_1 }, + { "gr", RTL_TEXTENCODING_ISO_8859_7 }, + { "he", RTL_TEXTENCODING_ISO_8859_8 }, + { "hi", RTL_TEXTENCODING_DONTKNOW }, + { "hr", RTL_TEXTENCODING_ISO_8859_2 }, + { "hu", RTL_TEXTENCODING_ISO_8859_2 }, + { "hy", RTL_TEXTENCODING_DONTKNOW }, + { "id", RTL_TEXTENCODING_ISO_8859_1 }, + { "is", RTL_TEXTENCODING_ISO_8859_1 }, + { "it", RTL_TEXTENCODING_ISO_8859_1 }, + { "iw", RTL_TEXTENCODING_ISO_8859_8 }, + { "ja", RTL_TEXTENCODING_EUC_JP }, + { "ka", RTL_TEXTENCODING_DONTKNOW }, + { "kk", RTL_TEXTENCODING_ISO_8859_5 }, + { "ko", RTL_TEXTENCODING_EUC_KR }, + { "lt", RTL_TEXTENCODING_ISO_8859_4 }, + { "lv", RTL_TEXTENCODING_ISO_8859_4 }, + { "mk", RTL_TEXTENCODING_ISO_8859_5 }, + { "mr", RTL_TEXTENCODING_DONTKNOW }, + { "ms", RTL_TEXTENCODING_ISO_8859_1 }, + { "nl", RTL_TEXTENCODING_ISO_8859_1 }, + { "no", RTL_TEXTENCODING_ISO_8859_1 }, + { "pl", RTL_TEXTENCODING_ISO_8859_2 }, + { "pt", RTL_TEXTENCODING_ISO_8859_1 }, + { "ro", RTL_TEXTENCODING_ISO_8859_2 }, + { "ru", RTL_TEXTENCODING_ISO_8859_5 }, + { "sa", RTL_TEXTENCODING_DONTKNOW }, + { "sk", RTL_TEXTENCODING_ISO_8859_2 }, + { "sl", RTL_TEXTENCODING_ISO_8859_2 }, + { "sq", RTL_TEXTENCODING_ISO_8859_2 }, + { "sv", RTL_TEXTENCODING_ISO_8859_1 }, + { "sw", RTL_TEXTENCODING_ISO_8859_1 }, + { "ta", RTL_TEXTENCODING_DONTKNOW }, + { "th", RTL_TEXTENCODING_DONTKNOW }, + { "tr", RTL_TEXTENCODING_ISO_8859_9 }, + { "tt", RTL_TEXTENCODING_ISO_8859_5 }, + { "uk", RTL_TEXTENCODING_ISO_8859_5 }, + { "ur", RTL_TEXTENCODING_ISO_8859_6 }, + { "uz", RTL_TEXTENCODING_ISO_8859_9 }, + { "vi", RTL_TEXTENCODING_DONTKNOW }, + { "zh", RTL_TEXTENCODING_BIG5 } +}; + +/***************************************************************************** + return the text encoding corresponding to the given locale + *****************************************************************************/ + +rtl_TextEncoding osl_getTextEncodingFromLocale( rtl_Locale * pLocale ) +{ + const _pair *language = 0; + char locale_buf[64] = ""; + char *cp; + + WinMessageBox(HWND_DESKTOP,HWND_DESKTOP, + "Please contact technical support and report above informations.\n\n", + "Critical error: osl_getTextEncodingFromLocale", + 0, MB_ERROR | MB_OK | MB_MOVEABLE); + + /* default to process locale if pLocale == NULL */ + if( NULL == pLocale ) + osl_getProcessLocale( &pLocale ); + + /* convert rtl_Locale to locale string */ + if( _compose_locale( pLocale, locale_buf, 64 ) ) + { + /* check special handling list (EUC) first */ + const unsigned int members = sizeof( _full_locale_list ) / sizeof( _pair ); + language = _pair_search( locale_buf, _full_locale_list, members); + + if( NULL == language ) + { + /* + * check if there is a charset qualifier at the end of the given locale string + * e.g. de.ISO8859-15 or de.ISO8859-15@euro which strongly indicates what + * charset to use + */ + cp = strrchr( locale_buf, '.' ); + + if( NULL != cp ) + { + const unsigned int members = sizeof( _locale_extension_list ) / sizeof( _pair ); + language = _pair_search( cp + 1, _locale_extension_list, members); + } + } + + /* use iso language code to determine the charset */ + if( NULL == language ) + { + const unsigned int members = sizeof( _iso_language_list ) / sizeof( _pair ); + + /* iso lang codes have 2 charaters */ + locale_buf[2] = '\0'; + + language = _pair_search( locale_buf, _iso_language_list, members); + } + } + + /* a matching item in our list provides a mapping from codeset to + * rtl-codeset */ + if ( language != NULL ) + return language->value; + + return RTL_TEXTENCODING_DONTKNOW; +} + +/***************************************************************************** + return the current process locale + *****************************************************************************/ + +void _imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + /* simulate behavior off setlocale */ + char * locale = getenv( "LC_ALL" ); + + if( NULL == locale ) + locale = getenv( "LC_CTYPE" ); + + if( NULL == locale ) + locale = getenv( "LANG" ); + + if( NULL == locale ) + locale = "C"; + + *ppLocale = _parse_locale( locale ); +} + +/***************************************************************************** + set the current process locale + *****************************************************************************/ + +int _imp_setProcessLocale( rtl_Locale * pLocale ) +{ + char locale_buf[64]; + + /* convert rtl_Locale to locale string */ + if( NULL != _compose_locale( pLocale, locale_buf, 64 ) ) + { + /* only change env vars that exist already */ + if( getenv( "LC_ALL" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) || defined( __EMX__ ) + setenv( "LC_ALL", locale_buf, 1); +#else + setenv( "LC_ALL", locale_buf ); +#endif + } + + if( getenv( "LC_CTYPE" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) || defined( __EMX__ ) + setenv("LC_CTYPE", locale_buf, 1 ); +#else + setenv( "LC_CTYPE", locale_buf ); +#endif + } + + if( getenv( "LANG" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) || defined( __EMX__ ) + setenv("LC_CTYPE", locale_buf, 1 ); +#else + setenv( "LANG", locale_buf ); +#endif + } + } + + return 0; +} + + diff --git a/sal/osl/os2/path_helper.cxx b/sal/osl/os2/path_helper.cxx new file mode 100644 index 000000000000..6425927a0021 --- /dev/null +++ b/sal/osl/os2/path_helper.cxx @@ -0,0 +1,116 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/******************************************************************* + Includes + ******************************************************************/ + +#include "path_helper.hxx" +#include <osl/diagnose.h> +#include <rtl/ustring.hxx> + +#include <algorithm> +#include <wchar.h> +#include <wctype.h> + +/******************************************************************* + Constants + ******************************************************************/ + +const rtl::OUString BACKSLASH = rtl::OUString::createFromAscii("\\"); +const rtl::OUString SLASH = rtl::OUString::createFromAscii("/"); + +/******************************************************************* + osl_systemPathEnsureSeparator + ******************************************************************/ + +void osl_systemPathEnsureSeparator(/*inout*/ rtl_uString** ppustrPath) +{ + OSL_PRECOND(ppustrPath && (NULL != *ppustrPath), \ + "osl_systemPathEnsureSeparator: Invalid parameter"); + + rtl::OUString path(*ppustrPath); + sal_Int32 i = std::max<sal_Int32>(path.lastIndexOf(BACKSLASH), path.lastIndexOf(SLASH)); + + if (i < (path.getLength()-1)) + { + path += BACKSLASH; + rtl_uString_assign(ppustrPath, path.pData); + } + + OSL_POSTCOND(path.lastIndexOf(BACKSLASH) == (path.getLength() - 1), \ + "osl_systemPathEnsureSeparator: Post condition failed"); +} + +/******************************************************************* + osl_systemPathRemoveSeparator + ******************************************************************/ + +void SAL_CALL osl_systemPathRemoveSeparator(/*inout*/ rtl_uString** ppustrPath) +{ + rtl::OUString path(*ppustrPath); + + if (!osl::systemPathIsLogicalDrivePattern(path)) + { + sal_Int32 i = std::max<sal_Int32>(path.lastIndexOf(BACKSLASH), path.lastIndexOf(SLASH)); + + if (i > -1 && (i == (path.getLength() - 1))) + { + path = rtl::OUString(path.getStr(), path.getLength() - 1); + rtl_uString_assign(ppustrPath, path.pData); + } + } +} + +/******************************************************************* + osl_is_logical_drive_pattern + ******************************************************************/ + +// is [A-Za-z]:[/|\]\0 +const sal_Unicode* LDP = L":"; +const sal_Unicode* LDP_WITH_BACKSLASH = L":\\"; +const sal_Unicode* LDP_WITH_SLASH = L":/"; + +// degenerated case returned by the Windows FileOpen dialog +// when someone enters for instance "x:filename", the Win32 +// API accepts this case +const sal_Unicode* LDP_WITH_DOT_BACKSLASH = L":.\\"; + +sal_Int32 osl_systemPathIsLogicalDrivePattern(/*in*/ const rtl_uString* pustrPath) +{ + const sal_Unicode* p = rtl_uString_getStr(const_cast<rtl_uString*>(pustrPath)); + if (iswalpha(*p++)) + { + return ((0 == wcscmp(p, LDP)) || + (0 == wcscmp(p, LDP_WITH_BACKSLASH)) || + (0 == wcscmp(p, LDP_WITH_SLASH)) || + (0 == wcscmp(p, LDP_WITH_DOT_BACKSLASH))); + } + return 0; +} + + diff --git a/sal/osl/os2/path_helper.h b/sal/osl/os2/path_helper.h new file mode 100644 index 000000000000..79341f538667 --- /dev/null +++ b/sal/osl/os2/path_helper.h @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _PATH_HELPER_H_ +#define _PATH_HELPER_H_ + +#include <sal/types.h> +#include <rtl/ustring.h> +#include <osl/file.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************* + osl_systemPathEnsureSeparator + Adds a trailing path separator to the given system path if not + already there and if the path is not the root path or a logical + drive alone + ******************************************************************/ + +void osl_systemPathEnsureSeparator(/*inout*/ rtl_uString** ppustrPath); + +/******************************************************************* + osl_systemPathRemoveSeparator + Removes the last separator from the given system path if any and + if the path is not the root path '\' + ******************************************************************/ + +void SAL_CALL osl_systemPathRemoveSeparator(/*inout*/ rtl_uString** ppustrPath); + +/******************************************************************* + osl_is_logical_drive_pattern + Returns whether a given path is only a logical drive pattern or not. + A logical drive pattern is something like "a:\", "c:\". + No logical drive pattern is something like "c:\test" + ******************************************************************/ + +sal_Int32 osl_systemPathIsLogicalDrivePattern(/*in*/ const rtl_uString* pustrPath); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sal/osl/os2/path_helper.hxx b/sal/osl/os2/path_helper.hxx new file mode 100644 index 000000000000..8a301431f610 --- /dev/null +++ b/sal/osl/os2/path_helper.hxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// YD #pragma warning (disable : 4800) + +#ifndef _PATH_HELPER_HXX_ +#define _PATH_HELPER_HXX_ + +#include "path_helper.h" +#include <rtl/ustring.hxx> + +namespace osl +{ + +/******************************************************************* + osl_systemPathEnsureSeparator + Adds a trailing path separator to the given system path if not + already there and if the path is not the root path or a logical + drive alone + ******************************************************************/ + +inline void systemPathEnsureSeparator(/*inout*/ rtl::OUString& Path) +{ + osl_systemPathEnsureSeparator(&Path.pData); +} + +/******************************************************************* + osl_systemPathRemoveSeparator + Removes the last separator from the given system path if any and + if the path is not the root path '\' + ******************************************************************/ + +inline void systemPathRemoveSeparator(/*inout*/ rtl::OUString& Path) +{ + osl_systemPathRemoveSeparator(&Path.pData); +} + +/******************************************************************* + osl_systemPathIsLogicalDrivePattern + ******************************************************************/ + +inline bool systemPathIsLogicalDrivePattern(/*in*/ const rtl::OUString& path) +{ + return osl_systemPathIsLogicalDrivePattern(path.pData); +} + +} // end namespace osl + +#endif diff --git a/sal/osl/os2/pipe.cxx b/sal/osl/os2/pipe.cxx new file mode 100644 index 000000000000..20db94bda9eb --- /dev/null +++ b/sal/osl/os2/pipe.cxx @@ -0,0 +1,555 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +//#define INCL_DOSERRORS +#include "system.h" + +#include <osl/pipe.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/mutex.h> +#include <osl/semaphor.h> +#include <osl/conditn.h> +#include <osl/interlck.h> +#include <osl/process.h> +#include <rtl/ustring.hxx> + +#define PIPENAMEMASK "OSL_PIPE_%s" +#define SECPIPENAMEMASK "OSL_PIPE_%s_%s" + +typedef enum { + MSG_SYN, + MSG_FIN, + MSG_DATA, + MSG_UNKNOWN +} MessageType; + +struct oslPipeImpl { + oslInterlockedCount m_Reference; + HPIPE hPipe; + HMTX m_NamedObject; + APIRET nLastError; + //oslSecurity m_Security; + sal_Bool m_bClosed; +}; + +/* default size for input/output buffer */ +static const ULONG ulBufSize = 4096; + +/* OS/2 path for pipes */ +static const CHAR pszPipePath[] = "\\PIPE\\"; +static const UCHAR nPipePathLen = sizeof (pszPipePath) - 1; + +/* global last error value to be returned from oslGetLastPipeError */ +static APIRET ngLastError; + +using rtl::OString; +using rtl::OUString; +using rtl::OUStringToOString; + +/*****************************************************************************/ +/* osl_create/destroy-PipeImpl */ +/*****************************************************************************/ + +static oslInterlockedCount nPipes = 0; + +oslPipe __osl_createPipeImpl(void) +{ + oslPipe pPipe; + + pPipe = (oslPipe) calloc(1,sizeof(struct oslPipeImpl)); + + pPipe->m_bClosed = sal_False; + pPipe->m_Reference = 1; + pPipe->hPipe = NULL; + pPipe->m_NamedObject = NULL; + + return pPipe; +} + +void __osl_destroyPipeImpl(oslPipe pPipe) +{ + if (pPipe != NULL) + { + DosCloseMutexSem( pPipe->m_NamedObject); + free(pPipe); + } +} + + +/*****************************************************************************/ +/* osl_createPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, + oslSecurity Security) +{ + oslPipe pPipe; + + ULONG ulAction; + CHAR strPipeNameBuffer [CCHMAXPATHCOMP]; + rtl_String* strPipeName=0; + sal_Char* pszPipeName=0; + + /* check parameters */ + OSL_ASSERT( ustrPipeName ); + //YD 17/04/06 OSL_ASSERT( Security == 0 ); + + /* allocate impl-structure */ + pPipe = __osl_createPipeImpl(); + if (!pPipe) + { + OSL_TRACE( "osl_createPipe failed allocating memory.\n" ); + return NULL; + } + + /* create pipe name */ + OString sPipe = OUStringToOString(ustrPipeName, RTL_TEXTENCODING_ASCII_US); +#if OSL_DEBUG_LEVEL>0 + debug_printf("osl_createPipe options 0x%x\n", Options); +#endif + + switch( Options ) + { + case osl_Pipe_OPEN: + { + APIRET fPipeAvailable; + + sprintf (strPipeNameBuffer, "\\PIPE\\OSL_PIPE_%s", sPipe.getStr()); +#if OSL_DEBUG_LEVEL>0 + debug_printf("osl_createPipe %s\n", strPipeNameBuffer); +#endif + ngLastError = DosOpen( (PCSZ)strPipeNameBuffer, + &(pPipe->hPipe), &ulAction, + 0, FILE_NORMAL, FILE_OPEN, + OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE, + (PEAOP2) NULL); + // if pipe is busy, wait for it + if (ngLastError == ERROR_PIPE_BUSY) + do + { + /* free instance should be available first */ + fPipeAvailable = DosWaitNPipe( (PCSZ)strPipeNameBuffer, -1); + /* first try to open system pipe */ + if ( fPipeAvailable == NO_ERROR ) + { + // We got it ! + ngLastError = NO_ERROR; + break; + } + // Pipe instance maybe catched by another client -> try again + printf("osl_createPipe wait for Pipe available\n"); + } while ( fPipeAvailable ); + } + break; + case osl_Pipe_CREATE: + { + sprintf (strPipeNameBuffer, "\\SEM32\\OSL_SEM_%s", sPipe.getStr()); + // check if semaphore exists (pipe create must fail for existig pipes) + ngLastError = DosCreateMutexSem( (PCSZ)strPipeNameBuffer, &(pPipe->m_NamedObject), 0, TRUE ); + if (ngLastError) + break; + + sprintf (strPipeNameBuffer, "\\PIPE\\OSL_PIPE_%s", sPipe.getStr()); +#if OSL_DEBUG_LEVEL>0 + debug_printf("osl_createPipe %s\n", strPipeNameBuffer); +#endif + ngLastError = DosCreateNPipe( (PCSZ)strPipeNameBuffer, + &(pPipe->hPipe), + NP_ACCESS_DUPLEX, /* open pipe for read and write access */ + 0xFF, /* allow unlimited number of instances */ + ulBufSize, /* output buffer size */ + ulBufSize, /* input buffer size */ + 0L /* use default time-out time */ + ); + } + break; + default: + ngLastError = ERROR_INVALID_PARAMETER; + } + + /* if failed, release allocated memory */ + if (ngLastError) + { + OSL_TRACE( "osl_createPipe failed %s the pipe %s, Error Code %d.\n", + Options == osl_Pipe_OPEN ? "opening" : "creating", + strPipeNameBuffer, + ngLastError ); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + + pPipe->m_Reference= 1; + pPipe->m_bClosed = sal_False; + //pPipe->m_Security = Security; + pPipe->nLastError = NO_ERROR; + return (oslPipe)pPipe; +} + +/*****************************************************************************/ +/* osl_copyPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_copyPipe(oslPipe pPipe) +{ + //oslPipe* pPipe = (oslPipe*) Pipe; + oslPipe pNewPipe; + + + /* check parameter */ + OSL_ASSERT (pPipe); + + /* allocate impl-structure */ + pNewPipe = __osl_createPipeImpl(); + if (!pNewPipe) return NULL; + + /* create new handle */ + pNewPipe->hPipe = (HPIPE) -1; + ngLastError = DosDupHandle( pPipe->hPipe, &(pNewPipe->hPipe) ); + + /* if failed, release allocated memory */ + if (ngLastError) + { + OSL_TRACE( "osl_copyPipe failed duplicating pipe handle, Error-Code: %d.\n", + ngLastError ); + free (pNewPipe); + return NULL; + } + + pNewPipe->nLastError = NO_ERROR; + return (oslPipe)pNewPipe; +} + +void SAL_CALL osl_acquirePipe( oslPipe pPipe ) +{ + osl_incrementInterlockedCount( &(pPipe->m_Reference) ); +} + +void SAL_CALL osl_releasePipe( oslPipe pPipe ) +{ +// OSL_ASSERT( pPipe ); + + if( 0 == pPipe ) + return; + + if( 0 == osl_decrementInterlockedCount( &(pPipe->m_Reference) ) ) + { + if( ! pPipe->m_bClosed ) + osl_closePipe( pPipe ); + + __osl_destroyPipeImpl( pPipe ); + } +} + +/*****************************************************************************/ +/* osl_destroyPipe */ +/*************close****************************************************************/ +void SAL_CALL osl_closePipe(oslPipe pPipe) +{ + //oslPipe* pPipe = (oslPipe*) Pipe; + /* check parameter */ + OSL_ASSERT (pPipe); + + if( pPipe && ! pPipe->m_bClosed ) + { + pPipe->m_bClosed = sal_True; + /* if we have a system pipe close it */ + if (pPipe->hPipe != 0) + { + /* disconnect client */ + DosDisConnectNPipe (pPipe->hPipe); + + /* close the pipe */ + DosClose (pPipe->hPipe); + } + } +} + +/*****************************************************************************/ +/* osl_acceptPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe) +{ + +#define PINFO ((PIPEINFO *) &PipeInfoBuffer) + + ///oslPipe* pPipe = (oslPipe*) Pipe; + oslPipe pNewPipe; + BYTE PipeInfoBuffer[sizeof(PIPEINFO) + CCHMAXPATHCOMP]; + + /* check parameter */ + OSL_ASSERT (pPipe); + + /* get pipe information */ + pPipe->nLastError = DosQueryNPipeInfo(pPipe->hPipe, + 1, + (PVOID) &PipeInfoBuffer, + sizeof(PipeInfoBuffer)); + + if (pPipe->nLastError) + { + OSL_TRACE( "osl_acceptPipe failed for requesting pipe information.\n", + pPipe->nLastError ); + return NULL; + } + + /* create a new instance of the pipe if possible */ + if (PINFO->cbMaxInst == -1 || /* unlimited instances */ + PINFO->cbMaxInst > PINFO->cbCurInst) + { + HPIPE hPipe; + + pNewPipe = __osl_createPipeImpl(); + + if (!pNewPipe) + { + OSL_TRACE( "osl_acceptPipe failed creating new instance.\n", ngLastError ); + free(pNewPipe); + return NULL; + } + + //pNewPipe->m_Security = pPipe->m_Security; + + pNewPipe->nLastError = + DosCreateNPipe( (PCSZ)PINFO->szName, + &(pNewPipe->hPipe), + NP_ACCESS_DUPLEX, /* open pipe for read and write access */ + 0xFF, /* allow unlimited number of instances */ + ulBufSize, /* output buffer size */ + ulBufSize, /* input buffer size */ + 0L /* use default time-out time */ + ); + + if (pNewPipe->nLastError) + { + OSL_TRACE( "osl_acceptPipe failed creating new named pipe, Error-Code: %d.\n", + pNewPipe->nLastError ); + free(pNewPipe); + return NULL; + } + + /* switch pipe handles */ + hPipe = pPipe->hPipe; + pPipe->hPipe = pNewPipe->hPipe; + pNewPipe->hPipe = hPipe; + + /* connect new handle to client */ + pNewPipe->nLastError = DosConnectNPipe( pNewPipe->hPipe ); + + /* if failed, release allocated memory */ + if (pNewPipe->nLastError) + { + OSL_TRACE( "osl_acceptPipe failed connecting pipe to client, Error-Code: %d.\n", + pNewPipe->nLastError ); + + osl_closePipe((oslPipe)pNewPipe); + return NULL; + } + return (oslPipe)pNewPipe; + } + else + { + /* connect original handle to client */ + pPipe->nLastError = DosConnectNPipe( pPipe->hPipe ); + + if (pPipe->nLastError) + { + OSL_TRACE( "osl_acceptPipe failed connecting pipe to client, Error-Code: %d.\n", + pPipe->nLastError ); + return NULL; + } + + return (oslPipe)pPipe; + } +} + +/*****************************************************************************/ +/* osl_receivePipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe, + void* pBuffer, + sal_Int32 BytesToRead) +{ + //oslPipe* pPipe = (oslPipe*) Pipe; + ULONG ulActual; + + /* check parameter */ + OSL_ASSERT (pPipe); + + /* read data from pipe */ + pPipe->nLastError = DosRead( pPipe->hPipe, pBuffer, BytesToRead, &ulActual ); + + /* return -1 if failed */ + if( pPipe->nLastError ) + { + OSL_TRACE( "osl_receivePipe failed receiving from Pipe, Error-Code: %d.\n", + pPipe->nLastError ); + return -1; + } + + return ulActual; +} + + +/*****************************************************************************/ +/* osl_sendPipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe, + const void* pBuffer, + sal_Int32 BytesToSend) +{ + //oslPipe* pPipe = (oslPipe*) Pipe; + ULONG ulActual; + + /* check parameter */ + OSL_ASSERT (pPipe); + + /* read data from pipe */ + pPipe->nLastError = DosWrite( pPipe->hPipe, (PVOID) pBuffer, BytesToSend, &ulActual ); + + /* return -1 if failed */ + if( pPipe->nLastError ) + { + OSL_TRACE( "osl_receivePipe failed writing to Pipe, Error-Code: %d.\n", + pPipe->nLastError ); + return -1; + } + + return ulActual; +} + + +/*****************************************************************************/ +/* osl_getLastPipeError */ +/*****************************************************************************/ + +oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe) +{ + //oslPipe* pPipe = (oslPipe*) Pipe; + APIRET rc; + + /* return local error value if possible */ + if (pPipe) + { + rc = pPipe->nLastError; + pPipe->nLastError = NO_ERROR; + } else + rc = ngLastError; + + /* map OS/2 error values */ + switch (rc) + { + case NO_ERROR: return osl_Pipe_E_None; + case ERROR_PATH_NOT_FOUND: return osl_Pipe_E_NotFound; + case ERROR_NOT_ENOUGH_MEMORY: return osl_Pipe_E_NoBufferSpace; + default: return osl_Pipe_E_invalidError; + } +} + +/*****************************************************************************/ + +sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n ) +{ + /* loop until all desired bytes were send or an error occured */ + sal_Int32 BytesSend= 0; + sal_Int32 BytesToSend= n; + + OSL_ASSERT(pPipe); + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToSend -= RetVal; + BytesSend += RetVal; + pBuffer= (sal_Char*)pBuffer + RetVal; + } + + return BytesSend; +} + +sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n ) +{ + /* loop until all desired bytes were read or an error occured */ + sal_Int32 BytesRead= 0; + sal_Int32 BytesToRead= n; + + OSL_ASSERT( pPipe ); + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToRead -= RetVal; + BytesRead += RetVal; + pBuffer= (sal_Char*)pBuffer + RetVal; + } + return BytesRead; +} + + +/****************************************************************************** + * + * New io resource transfer functions + * + *****************************************************************************/ + + +/********************************************** + osl_sendResourcePipe + *********************************************/ + +sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket) +{ + sal_Bool bRet = sal_False; + + return bRet; +} + +/********************************************** + osl_receiveResourcePipe + *********************************************/ + +oslSocket osl_receiveResourcePipe(oslPipe pPipe) +{ + oslSocket pSocket=0; + + return (oslSocket) pSocket; +} + + diff --git a/sal/osl/os2/pipeimpl.cxx b/sal/osl/os2/pipeimpl.cxx new file mode 100644 index 000000000000..d08a370c428c --- /dev/null +++ b/sal/osl/os2/pipeimpl.cxx @@ -0,0 +1,755 @@ +# include "pipeimpl.h" + +#ifndef _INC_MALLOC +# include <malloc.h> +#endif + +#ifndef _INC_TCHAR +# ifdef UNICODE +# define _UNICODE +# endif +# include <tchar.h> +#endif + +const TCHAR PIPE_NAME_PREFIX_MAPPING[] = TEXT("PIPE_FILE_MAPPING_"); +const TCHAR PIPE_NAME_PREFIX_SYNCHRONIZE[] = TEXT("PIPE_SYNCHRONIZE_MUTEX_"); +const TCHAR PIPE_NAME_PREFIX_CONNECTION[] = TEXT("PIPE_CONNECTION_SEMAPHORE_"); + +const DWORD PIPE_BUFFER_SIZE = 4096; + + +//============================================================================ +// PipeData +//============================================================================ + +struct PipeData +{ + DWORD dwProcessId; + HANDLE hReadPipe; + HANDLE hWritePipe; +}; + +//============================================================================ +// Pipe +//============================================================================ + +#ifdef UNICODE +#define Pipe PipeW +#define ClientPipe ClientPipeW +#define ServerPipe ServerPipeW +#else +#define Pipe PipeA +#define ClientPipe ClientPipeA +#define ServerPipe ServerPipeA +#endif + +class Pipe +{ +protected: + HANDLE m_hReadPipe; // Handle to use for reading + HANDLE m_hWritePipe; // Handle to use for writing + + Pipe( HANDLE hReadPipe, HANDLE hWritePipe ); + + static HANDLE CreatePipeDataMutex( LPCTSTR lpName, BOOL bInitialOwner ); + static HANDLE CreatePipeDataMapping( LPCTSTR lpName ); + static HANDLE OpenPipeDataMapping( LPCTSTR lpName ); + static HANDLE CreatePipeConnectionSemaphore( LPCTSTR lpName, LONG lInitialCount, LONG lMaximumcount ); + +public: + Pipe( const Pipe& ); + const Pipe& operator = ( const Pipe& ); + virtual ~Pipe(); + + virtual bool Close(); + virtual bool Write( LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, bool bWait = true ); + virtual bool Read( LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, bool bWait = true ); + + virtual Pipe *AcceptConnection() + { + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } + + void * operator new( size_t nBytes ) + { + return HeapAlloc( GetProcessHeap(), 0, nBytes ); + } + + void operator delete( void *ptr ) + { + HeapFree( GetProcessHeap(), 0, ptr ); + } + + bool is() const + { + return (FALSE != HeapValidate( GetProcessHeap(), 0, this )); + } + +}; + +//============================================================================ +// ClientPipe +//============================================================================ + +class ClientPipe : public Pipe +{ +protected: + ClientPipe( HANDLE hReadPipe, HANDLE hWritePipe ); +public: + static ClientPipe* Create( LPCTSTR lpName ); +}; + +//============================================================================ +// ServerPipe +//============================================================================ + +class ServerPipe : public Pipe +{ +protected: + HANDLE m_hMapping; + HANDLE m_hSynchronize; + LPTSTR m_lpName; + + ServerPipe( LPCTSTR lpName, HANDLE hMapping, HANDLE hSynchronize, HANDLE hReadPipe, HANDLE hWritePipe ); +public: + virtual ~ServerPipe(); + + static ServerPipe *Create( LPCTSTR lpName ); + + virtual Pipe *AcceptConnection(); +}; + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HANDLE Pipe::CreatePipeDataMapping( LPCTSTR lpName ) +{ + HANDLE hMapping = NULL; + LPTSTR lpMappingName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_MAPPING) ); + + if ( lpMappingName ) + { + _tcscpy( lpMappingName, PIPE_NAME_PREFIX_MAPPING ); + _tcscat( lpMappingName, lpName ); + + LPTSTR lpMappingFileName = (LPTSTR)alloca( MAX_PATH * sizeof(TCHAR) ); + + if ( lpMappingFileName ) + { + DWORD nChars = GetTempPath( MAX_PATH, lpMappingFileName ); + + if ( MAX_PATH + _tcslen(lpName) < nChars + 1 ) + { + lpMappingFileName = (LPTSTR)alloca( (nChars + 1 + _tcslen(lpName)) * sizeof(TCHAR) ); + if ( lpMappingFileName ) + nChars = GetTempPath( nChars, lpMappingFileName ); + else + { + nChars = 0; + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + } + } + + if ( nChars ) + { + _tcscat( lpMappingFileName, lpMappingName ); + + HANDLE hFile = CreateFile( + lpMappingFileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + NULL ); + + if ( IsValidHandle(hFile) ) + { + hMapping = CreateFileMapping( + (HANDLE)hFile, + (LPSECURITY_ATTRIBUTES)NULL, + PAGE_READWRITE, + 0, + sizeof(PipeData), + lpMappingName ); + + CloseHandle( hFile ); + } + } + } + else + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + } + + return hMapping; +} + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HANDLE Pipe::OpenPipeDataMapping( LPCTSTR lpName ) +{ + HANDLE hMapping = NULL; + LPTSTR lpMappingName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_MAPPING) ); + + if ( lpMappingName ) + { + _tcscpy( lpMappingName, PIPE_NAME_PREFIX_MAPPING ); + _tcscat( lpMappingName, lpName ); + + hMapping = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, lpMappingName ); + } + + return hMapping; +} + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HANDLE Pipe::CreatePipeDataMutex( LPCTSTR lpName, BOOL bInitialOwner ) +{ + HANDLE hMutex = NULL; + LPTSTR lpMutexName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_SYNCHRONIZE) ); + + if ( lpMutexName ) + { + _tcscpy( lpMutexName, PIPE_NAME_PREFIX_SYNCHRONIZE ); + _tcscat( lpMutexName, lpName ); + + hMutex = CreateMutex( NULL, bInitialOwner, lpMutexName ); + } + + return hMutex; +} + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HANDLE Pipe::CreatePipeConnectionSemaphore( LPCTSTR lpName, LONG lInitialCount, LONG lMaximumCount ) +{ + HANDLE hSemaphore = NULL; + LPTSTR lpSemaphoreName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_CONNECTION) ); + + if ( lpSemaphoreName ) + { + _tcscpy( lpSemaphoreName, PIPE_NAME_PREFIX_CONNECTION ); + _tcscat( lpSemaphoreName, lpName ); + + hSemaphore = CreateSemaphore( NULL, lInitialCount, lMaximumCount, lpSemaphoreName ); + } + + return hSemaphore; +} + + +//---------------------------------------------------------------------------- +// Pipe copy ctor +//---------------------------------------------------------------------------- + +Pipe::Pipe( const Pipe& rPipe ) : +m_hReadPipe( INVALID_HANDLE_VALUE ), +m_hWritePipe( INVALID_HANDLE_VALUE ) +{ + DuplicateHandle( + GetCurrentProcess(), + rPipe.m_hReadPipe, + GetCurrentProcess(), + &m_hReadPipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + DuplicateHandle( + GetCurrentProcess(), + rPipe.m_hWritePipe, + GetCurrentProcess(), + &m_hWritePipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); +} + +//---------------------------------------------------------------------------- +// Pipe assignment operator +//---------------------------------------------------------------------------- + +const Pipe& Pipe::operator = ( const Pipe& rPipe ) +{ + Close(); + + DuplicateHandle( + GetCurrentProcess(), + rPipe.m_hReadPipe, + GetCurrentProcess(), + &m_hReadPipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + DuplicateHandle( + GetCurrentProcess(), + rPipe.m_hWritePipe, + GetCurrentProcess(), + &m_hWritePipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + return *this; +} + +//---------------------------------------------------------------------------- +// Pipe ctor +//---------------------------------------------------------------------------- + +Pipe::Pipe( HANDLE hReadPipe, HANDLE hWritePipe ) : +m_hReadPipe( INVALID_HANDLE_VALUE ), +m_hWritePipe( INVALID_HANDLE_VALUE ) +{ + DuplicateHandle( + GetCurrentProcess(), + hReadPipe, + GetCurrentProcess(), + &m_hReadPipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + DuplicateHandle( + GetCurrentProcess(), + hWritePipe, + GetCurrentProcess(), + &m_hWritePipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); +} + +//---------------------------------------------------------------------------- +// Pipe dtor +//---------------------------------------------------------------------------- + +Pipe::~Pipe() +{ + Close(); +} + +//---------------------------------------------------------------------------- +// Pipe Close +//---------------------------------------------------------------------------- + +bool Pipe::Close() +{ + bool fSuccess = false; // Assume failure + + if ( IsValidHandle(m_hReadPipe) ) + { + CloseHandle( m_hReadPipe ); + m_hReadPipe = INVALID_HANDLE_VALUE; + } + + if ( IsValidHandle(m_hWritePipe) ) + { + CloseHandle( m_hWritePipe ); + m_hWritePipe = INVALID_HANDLE_VALUE; + } + + return fSuccess; +} + +//---------------------------------------------------------------------------- +// Pipe Write +//---------------------------------------------------------------------------- + +bool Pipe::Write( LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, bool bWait ) +{ + DWORD dwBytesAvailable = 0; + BOOL fSuccess = TRUE; + + if ( !bWait ) + fSuccess = PeekNamedPipe( m_hReadPipe, NULL, 0, NULL, &dwBytesAvailable, NULL ); + + if ( fSuccess ) + { + if ( !bWait && dwBytesToWrite > PIPE_BUFFER_SIZE - dwBytesAvailable ) + dwBytesToWrite = PIPE_BUFFER_SIZE - dwBytesAvailable ; + + return !!WriteFile( m_hWritePipe, lpBuffer, dwBytesToWrite, lpBytesWritten, NULL ); + } + + return false; +} + +//---------------------------------------------------------------------------- +// Pipe Read +//---------------------------------------------------------------------------- + +bool Pipe::Read( LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, bool bWait ) +{ + DWORD dwBytesAvailable = 0; + BOOL fSuccess = TRUE; + + if ( !bWait ) + fSuccess = PeekNamedPipe( m_hReadPipe, NULL, 0, NULL, &dwBytesAvailable, NULL ); + + if ( fSuccess ) + { + if ( bWait || dwBytesAvailable ) + return !!ReadFile( m_hReadPipe, lpBuffer, dwBytesToRead, lpBytesRead, NULL ); + else + { + *lpBytesRead = 0; + return true; + } + } + + return false; +} + + + +//---------------------------------------------------------------------------- +// Client pipe dtor +//---------------------------------------------------------------------------- + +ClientPipe::ClientPipe( HANDLE hReadPipe, HANDLE hWritePipe ) : Pipe( hReadPipe, hWritePipe ) +{ +} + +//---------------------------------------------------------------------------- +// Client pipe creation +//---------------------------------------------------------------------------- + +ClientPipe *ClientPipe::Create( LPCTSTR lpName ) +{ + ClientPipe *pPipe = NULL; // Assume failure + + HANDLE hMapping = OpenPipeDataMapping( lpName ); + + if ( IsValidHandle(hMapping) ) + { + PipeData *pData = (PipeData*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); + + if ( pData ) + { + HANDLE hSourceProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, pData->dwProcessId ); + + if ( IsValidHandle(hSourceProcess) ) + { + BOOL fSuccess; + HANDLE hReadPipe = INVALID_HANDLE_VALUE, hWritePipe = INVALID_HANDLE_VALUE; + + fSuccess = DuplicateHandle( + hSourceProcess, + pData->hReadPipe, + GetCurrentProcess(), + &hReadPipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + fSuccess = fSuccess && DuplicateHandle( + hSourceProcess, + pData->hWritePipe, + GetCurrentProcess(), + &hWritePipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + if ( fSuccess ) + pPipe = new ClientPipe( hReadPipe, hWritePipe ); + + if ( IsValidHandle(hWritePipe) ) + CloseHandle( hWritePipe ); + + if ( IsValidHandle(hReadPipe) ) + CloseHandle( hReadPipe ); + + HANDLE hConnectionRequest = CreatePipeConnectionSemaphore( lpName, 0, 1 ); + + ReleaseSemaphore( hConnectionRequest, 1, NULL ); + + CloseHandle( hConnectionRequest ); + + CloseHandle( hSourceProcess ); + } + + UnmapViewOfFile( pData ); + } + + CloseHandle( hMapping ); + } + + return pPipe; +} + + + +//---------------------------------------------------------------------------- +// ServerPipe ctor +//---------------------------------------------------------------------------- + +ServerPipe::ServerPipe( LPCTSTR lpName, HANDLE hMapping, HANDLE hSynchronize, HANDLE hReadPipe, HANDLE hWritePipe ) : Pipe( hReadPipe, hWritePipe ), +m_hMapping( NULL ), +m_hSynchronize( NULL ), +m_lpName( NULL ) +{ + DuplicateHandle( + GetCurrentProcess(), + hMapping, + GetCurrentProcess(), + &m_hMapping, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + DuplicateHandle( + GetCurrentProcess(), + hSynchronize, + GetCurrentProcess(), + &m_hSynchronize, + 0, + FALSE, + DUPLICATE_SAME_ACCESS + ); + m_lpName = new TCHAR[_tcslen(lpName) + 1]; + if ( m_lpName ) + _tcscpy( m_lpName, lpName ); +} + +//---------------------------------------------------------------------------- +// ServerPipe dtor +//---------------------------------------------------------------------------- + +ServerPipe::~ServerPipe() +{ + if ( IsValidHandle(m_hMapping) ) + CloseHandle( m_hMapping ); + if ( m_lpName ) + delete[]m_lpName; +} + +//---------------------------------------------------------------------------- +// ServerPipe AcceptConnection +//---------------------------------------------------------------------------- + +Pipe *ServerPipe::AcceptConnection() +{ + Pipe *pPipe = NULL; // Assume failure; + + HANDLE hConnectionRequest = CreatePipeConnectionSemaphore( m_lpName, 0, 1 ); + + if ( WAIT_OBJECT_0 == WaitForSingleObject( hConnectionRequest, INFINITE ) ) + { + pPipe = new Pipe( *this ); + Close(); + + // Create new inbound Pipe + + HANDLE hClientWritePipe = NULL, hServerReadPipe = NULL; + + BOOL fSuccess = CreatePipe( &hServerReadPipe, &hClientWritePipe, NULL, PIPE_BUFFER_SIZE ); + + + if ( fSuccess ) + { + // Create outbound pipe + + HANDLE hClientReadPipe = NULL, hServerWritePipe = NULL; + + if ( CreatePipe( &hClientReadPipe, &hServerWritePipe, NULL, PIPE_BUFFER_SIZE ) ) + { + m_hReadPipe = hServerReadPipe; + m_hWritePipe = hServerWritePipe; + + PipeData *pData = (PipeData *)MapViewOfFile( m_hMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(PipeData) ); + + HANDLE hSynchronize = CreatePipeDataMutex( m_lpName, TRUE ); + + CloseHandle( pData->hReadPipe ); + CloseHandle( pData->hWritePipe ); + + pData->hReadPipe = hClientReadPipe; + pData->hWritePipe = hClientWritePipe; + + ReleaseMutex( hSynchronize ); + + CloseHandle( hSynchronize ); + + } + else + { + CloseHandle( hClientWritePipe ); + CloseHandle( hServerWritePipe ); + } + } + + ReleaseMutex( hConnectionRequest ); + } + + CloseHandle( hConnectionRequest ); + + return pPipe; +} + +//---------------------------------------------------------------------------- +// Pipe creation +//---------------------------------------------------------------------------- + +ServerPipe *ServerPipe::Create( LPCTSTR lpName ) +{ + ServerPipe *pPipe = NULL; + + HANDLE hMapping = CreatePipeDataMapping( lpName ); + + if ( IsValidHandle(hMapping) ) + { + if ( ERROR_FILE_EXISTS != GetLastError() ) + { + HANDLE hSynchronize = CreatePipeDataMutex( lpName, FALSE); + + WaitForSingleObject( hSynchronize, INFINITE ); + + PipeData *pData = (PipeData*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); + + if ( pData ) + { + + // Initialize pipe data + + pData->dwProcessId = 0; + pData->hReadPipe = NULL; + pData->hWritePipe = NULL; + + // Create inbound pipe + + HANDLE hServerReadPipe = NULL, hClientWritePipe = NULL; + + BOOL fSuccess = CreatePipe( &hServerReadPipe, &hClientWritePipe, NULL, PIPE_BUFFER_SIZE ); + + if ( fSuccess ) + { + // Create outbound pipe + + HANDLE hServerWritePipe = NULL, hClientReadPipe = NULL; + + fSuccess = CreatePipe( &hClientReadPipe, &hServerWritePipe, NULL, PIPE_BUFFER_SIZE ); + + if ( fSuccess ) + { + pData->dwProcessId = GetCurrentProcessId(); + pData->hReadPipe = hClientReadPipe; + pData->hWritePipe = hClientWritePipe; + pPipe = new ServerPipe( lpName, hMapping, hSynchronize, hServerReadPipe, hServerWritePipe ); + + CloseHandle( hServerWritePipe ); + CloseHandle( hServerReadPipe ); + } + else + { + CloseHandle( hServerReadPipe ); + CloseHandle( hClientWritePipe ); + } + } + + UnmapViewOfFile( pData ); + } + + ReleaseMutex( hSynchronize ); + CloseHandle( hSynchronize ); + } + + CloseHandle( hMapping ); + } + + return pPipe; +} + + +//---------------------------------------------------------------------------- +// C style API +//---------------------------------------------------------------------------- + +const TCHAR LOCAL_PIPE_PREFIX[] = TEXT("\\\\.\\PIPE\\" ); + +extern "C" HANDLE WINAPI CreateSimplePipe( LPCTSTR lpName ) +{ + int nPrefixLen = _tcslen( LOCAL_PIPE_PREFIX ); + if ( 0 == _tcsnicmp( lpName, LOCAL_PIPE_PREFIX, nPrefixLen ) ) + lpName += nPrefixLen; + return (HANDLE)ServerPipe::Create( lpName ); +} + +extern "C" HANDLE WINAPI OpenSimplePipe( LPCTSTR lpName ) +{ + int nPrefixLen = _tcslen( LOCAL_PIPE_PREFIX ); + if ( 0 == _tcsnicmp( lpName, LOCAL_PIPE_PREFIX, nPrefixLen ) ) + lpName += nPrefixLen; + return (HANDLE)ClientPipe::Create( lpName ); +} + +extern "C" HANDLE WINAPI AcceptSimplePipeConnection( HANDLE hPipe ) +{ + Pipe *pPipe = (Pipe *)hPipe; + + if ( pPipe->is() ) + return (HANDLE)pPipe->AcceptConnection(); + else + { + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } +} + +extern "C" BOOL WINAPI WaitForSimplePipe( LPCTSTR /*lpName*/, DWORD /*dwTimeOut*/ ) +{ + return FALSE; +} + +extern "C" BOOL WINAPI WriteSimplePipe( HANDLE hPipe, LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, BOOL bWait ) +{ + Pipe *pPipe = (Pipe *)hPipe; + + if ( pPipe->is() ) + return pPipe->Write( lpBuffer, dwBytesToWrite, lpBytesWritten, bWait ); + else + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } +} + +extern "C" BOOL WINAPI ReadSimplePipe( HANDLE hPipe, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, BOOL bWait ) +{ + Pipe *pPipe = (Pipe *)hPipe; + + if ( pPipe->is() ) + return pPipe->Read( lpBuffer, dwBytesToRead, lpBytesRead, bWait ); + else + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } +} + +extern "C" BOOL WINAPI CloseSimplePipe( HANDLE hPipe ) +{ + Pipe *pPipe = (Pipe *)hPipe; + + if ( pPipe->is() ) + { + delete pPipe; + return TRUE; + } + else + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } +} diff --git a/sal/osl/os2/pipeimpl.h b/sal/osl/os2/pipeimpl.h new file mode 100644 index 000000000000..cff082dee5a3 --- /dev/null +++ b/sal/osl/os2/pipeimpl.h @@ -0,0 +1,82 @@ +#ifndef _PIPEIMPL_H_ +#define _PIPEIMPL_H_ + +#ifndef _WINDOWS_ +# include <windows.h> +#endif + +#ifndef _INC_MALLOC +# include <malloc.h> +#endif + +#ifndef _INC_TCHAR +# ifdef UNICODE +# define _UNICODE +# endif +# include <tchar.h> +#endif + +#define EXPORT_PIPE_API + +//============================================================================ +// Helper functions +//============================================================================ + +// Because the value of an invalid HANDLE returned by API functions differs +// between different functions and differs on different Windows platforms, +// this function checks wether the handle has a meaningfull value. +#ifndef __cplusplus + +#define IsValidHandle( handle ) ((DWORD)(handle) + 1 > 1) + +#else + +inline bool IsValidHandle( HANDLE handle ) +{ + return INVALID_HANDLE_VALUE != handle && NULL != handle; +} + +extern "C" { + +#endif // __cplusplus + + +EXPORT_PIPE_API HANDLE WINAPI CreateSimplePipeA( LPCSTR lpName ); +EXPORT_PIPE_API HANDLE WINAPI CreateSimplePipeW( LPCWSTR lpName ); + +#ifdef UNICODE +#define CreateSimplePipe CreateSimplePipeW +#else +#define CreateSimplePipe CreateSimplePipeA +#endif + +EXPORT_PIPE_API HANDLE WINAPI OpenSimplePipeA( LPCSTR lpName ); +EXPORT_PIPE_API HANDLE WINAPI OpenSimplePipeW( LPCWSTR lpName ); + +#ifdef UNICODE +#define OpenSimplePipe OpenSimplePipeW +#else +#define OpenSimplePipe OpenSimplePipeA +#endif + +EXPORT_PIPE_API HANDLE WINAPI AcceptSimplePipeConnection( HANDLE hPipe ); + +EXPORT_PIPE_API BOOL WINAPI WaitForSimplePipeA( LPCSTR lpName, DWORD dwTimeOut ); +EXPORT_PIPE_API BOOL WINAPI WaitForSimplePipeW( LPCWSTR lpName, DWORD dwTimeOut ); + +#ifdef UNICODE +#define WaitForSimplePipe WaitForSimplePipeW +#else +#define WaitForSimplePipe WaitForSimplePipeA +#endif + + +EXPORT_PIPE_API BOOL WINAPI WriteSimplePipe( HANDLE hPipe, LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, BOOL bWait ); +EXPORT_PIPE_API BOOL WINAPI ReadSimplePipe( HANDLE hPipe, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, BOOL bWait ); +EXPORT_PIPE_API BOOL WINAPI CloseSimplePipe( HANDLE hPipe ); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PIPEIMPL_H_ diff --git a/sal/osl/os2/process.c b/sal/osl/os2/process.c new file mode 100644 index 000000000000..e83552192bfb --- /dev/null +++ b/sal/osl/os2/process.c @@ -0,0 +1,1013 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" +#include <osl/thread.h> + +#include <osl/diagnose.h> +//#include <osl/socket.h> + +#ifndef _OSL_FILE_PATH_HELPER_H_ +#include "file_path_helper.h" +#endif + +#include "procimpl.h" +//#include "sockimpl.h" +//#include "secimpl.h" + +#include <ctype.h> + +//#ifndef _RTL_USTRING_HXX_ +#include <rtl/ustring.hxx> +//#endif + +// for exception logging +#include <stdio.h> +#include <setjmp.h> +#include "helpers/except.h" + + +#define MAX_ARGS 255 +#define PIPENAMEMASK "\\PIPE\\OSL_PIPE_%u" +#define SEMNAMEMASK "\\SEM32\\OSL_SEM_%u" + +typedef enum { + MSG_DATA, + MSG_END, + MSG_ACK, + MSG_REL, + MSG_UNKNOWN +} MessageType; + +typedef struct { + MessageType m_Type; + oslDescriptorFlag m_Flags; + oslDescriptorType m_Data; + HANDLE m_Value; +} Message; + +typedef struct { + HPIPE m_hPipe; +} Pipe; + +typedef struct _oslSocketCallbackArg { + HANDLE m_socket; + Pipe* m_pipe; +} oslSocketCallbackArg; + +/* process termination queue */ +static sal_Bool bInitSessionTerm = sal_False; +static const sal_Char * const SessionTermQueueName = "\\QUEUES\\SESSIONS.QUE"; +static HQUEUE SessionTermQueue; + +/****************************************************************************** + * + * Function Declarations + * + *****************************************************************************/ + +oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, + sal_Char *pszArguments[], + oslProcessOption Options, + oslSecurity Security, + sal_Char *pszDirectory, + sal_Char *pszEnvironments[], + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead ); + +/* implemented in file.c */ +extern oslFileError FileURLToPath( char *, size_t, rtl_uString* ); + +static sal_Bool InitSessionTerm( void ) +{ + DosCreateQueue( &SessionTermQueue, QUE_FIFO, (PCSZ) SessionTermQueueName ); + + return sal_True; +} + +/****************************************************************************** + * + * Functions for starting a process + * + *****************************************************************************/ + +/********************************************** + osl_executeProcess_WithRedirectedIO + *********************************************/ + +oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO( + rtl_uString *ustrImageName, + rtl_uString *ustrArguments[], + sal_uInt32 nArguments, + oslProcessOption Options, + oslSecurity Security, + rtl_uString *ustrWorkDir, + rtl_uString *ustrEnvironment[], + sal_uInt32 nEnvironmentVars, + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead + ) +{ + + oslProcessError Error; + sal_Char* pszWorkDir=0; + sal_Char** pArguments=0; + sal_Char** pEnvironment=0; + unsigned int index; + + char szImagePath[PATH_MAX] = ""; + char szWorkDir[PATH_MAX] = ""; + +#if 0 + if (Options & osl_Process_SEARCHPATH) + { + const rtl::OUString PATH1; + OUString PATH (RTL_CONSTASCII_USTRINGPARAM("PATH")); + + rtl_uString * pSearchPath = 0; + osl_getEnvironment (PATH.pData, &pSearchPath); + if (pSearchPath) + { + rtl_uString * pSearchResult = 0; + osl_searchPath (ustrImageName, pSearchPath, &pSearchResult); + if (pSearchResult) + { + rtl_uString_assign (ustrImageName, pSearchResult); + rtl_uString_release (pSearchResult); + } + rtl_uString_release (pSearchPath); + } + } +#endif + + if ( ustrImageName && ustrImageName->length ) + { + FileURLToPath( szImagePath, PATH_MAX, ustrImageName ); + } + + if ( ustrWorkDir != 0 && ustrWorkDir->length ) + { + FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir ); + pszWorkDir = szWorkDir; + } + + if ( pArguments == 0 && nArguments > 0 ) + { + pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) ); + } + + + for ( index = 0 ; index < nArguments ; ++index ) + { + rtl_String* strArg =0; + + + rtl_uString2String( &strArg, + rtl_uString_getStr(ustrArguments[index]), + rtl_uString_getLength(ustrArguments[index]), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + + pArguments[index]=strdup(rtl_string_getStr(strArg)); + rtl_string_release(strArg); + pArguments[index+1]=0; + } + + for ( index = 0 ; index < nEnvironmentVars ; ++index ) + { + rtl_String* strEnv=0; + + if ( pEnvironment == 0 ) + { + pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) ); + } + + rtl_uString2String( &strEnv, + rtl_uString_getStr(ustrEnvironment[index]), + rtl_uString_getLength(ustrEnvironment[index]), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + + pEnvironment[index]=strdup(rtl_string_getStr(strEnv)); + rtl_string_release(strEnv); + pEnvironment[index+1]=0; + } + + int rc, pid; + int saveOutput = -1, saveInput = -1, saveError = -1; + int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 }; + FILE *i, *o, *e; + + if (pInputWrite) + pipe( stdInput); + if (pOutputRead) + pipe( stdOutput); + if (pErrorRead) + pipe( stdError); + + fcntl( stdInput[0], F_SETFD, FD_CLOEXEC); + fcntl( stdInput[1], F_SETFD, FD_CLOEXEC); + fcntl( stdOutput[0], F_SETFD, FD_CLOEXEC); + fcntl( stdOutput[1], F_SETFD, FD_CLOEXEC); + fcntl( stdError[0], F_SETFD, FD_CLOEXEC); + fcntl( stdError[1], F_SETFD, FD_CLOEXEC); + + saveInput = dup( STDIN_FILENO); + fcntl( saveInput, F_SETFD, FD_CLOEXEC); + dup2( stdInput[0], STDIN_FILENO ); + close( stdInput[0] ); + + saveOutput = dup( STDOUT_FILENO); + fcntl( saveOutput, F_SETFD, FD_CLOEXEC); + dup2( stdOutput[1], STDOUT_FILENO ); + close( stdOutput[1] ); + + saveError = dup( STDERR_FILENO); + fcntl( saveError, F_SETFD, FD_CLOEXEC); + dup2( stdError[1], STDERR_FILENO ); + close( stdError[1] ); + + Error = osl_psz_executeProcess(szImagePath, + pArguments, + Options, + Security, + pszWorkDir, + pEnvironment, + pProcess, + pInputWrite, + pOutputRead, + pErrorRead + ); + + if ( pInputWrite ) + *(pInputWrite) = osl_createFileHandleFromFD( stdInput[1] ); + + if ( pOutputRead ) + *(pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] ); + + if ( pErrorRead ) + *(pErrorRead) = osl_createFileHandleFromFD( stdError[0] ); + + // restore handles + dup2( saveInput, STDIN_FILENO); + close( saveInput); + dup2( saveOutput, STDOUT_FILENO); + close( saveOutput); + dup2( saveError, STDERR_FILENO); + close( saveError); + + if ( pArguments != 0 ) + { + for ( index = 0 ; index < nArguments ; ++index ) + { + if ( pArguments[index] != 0 ) + { + free(pArguments[index]); + } + } + free(pArguments); + } + + if ( pEnvironment != 0 ) + { + for ( index = 0 ; index < nEnvironmentVars ; ++index ) + { + if ( pEnvironment[index] != 0 ) + { + free(pEnvironment[index]); + } + } + free(pEnvironment); + } + + return Error; +} + +/********************************************** + osl_executeProcess + *********************************************/ + +oslProcessError SAL_CALL osl_executeProcess( + rtl_uString *ustrImageName, + rtl_uString *ustrArguments[], + sal_uInt32 nArguments, + oslProcessOption Options, + oslSecurity Security, + rtl_uString *ustrWorkDir, + rtl_uString *ustrEnvironment[], + sal_uInt32 nEnvironmentVars, + oslProcess *pProcess + ) +{ + return osl_executeProcess_WithRedirectedIO( + ustrImageName, + ustrArguments, + nArguments, + Options, + Security, + ustrWorkDir, + ustrEnvironment, + nEnvironmentVars, + pProcess, + NULL, + NULL, + NULL + ); +} + +/********************************************** + osl_psz_executeProcess + *********************************************/ + +oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, + sal_Char *pszArguments[], + oslProcessOption Options, + oslSecurity Security, + sal_Char *pszDirectory, + sal_Char *pszEnvironments[], + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead + ) +{ + ULONG ulSessID = 0; /* Session ID returned */ + PID pidProcess; + APIRET rc; + sal_Char* pStr; + sal_Char* args; + sal_Char* envs; + int i; + int n = 1; + oslProcessImpl* pProcImpl; + ULONG nAppType, nOwnAppType; + ULONG nCurrentDisk, nDriveMap, nBufSize; + int first = 0; + sal_Char path[ _MAX_PATH ]; + sal_Char currentDir[ _MAX_PATH ]; + sal_Char ownfilename[ _MAX_PATH ]; + RESULTCODES resultCode; + char** p; + + /* get imagename from arg list, if not specified */ + if (pszImageName == NULL) + pszImageName = pszArguments[first++]; + + OSL_ASSERT(pszImageName != NULL); + + /* check application type */ + rc = DosQueryAppType( (PCSZ) pszImageName, &nAppType ); + if( rc != NO_ERROR ) + { + if( (rc == ERROR_FILE_NOT_FOUND) || (rc == ERROR_PATH_NOT_FOUND) ) + return osl_Process_E_NotFound; + else + return osl_Process_E_Unknown; + } + + /* backup current disk information */ + if(DosQueryCurrentDisk(&nCurrentDisk, &nDriveMap)) + { + nCurrentDisk = 0; + } + + /* backup current directory information */ + nBufSize = _MAX_PATH; + if(DosQueryCurrentDir(0, (BYTE*)currentDir, &nBufSize)) + { + *currentDir = '\0'; + } + + /* change to working directory */ + if(pszDirectory && pszDirectory[1] == ':') + { + BYTE nDrive = toupper(pszDirectory[0]) - 'A' + 1; + + if(NO_ERROR == DosSetDefaultDisk(nDrive)) + { + DosSetCurrentDir((PSZ) pszDirectory); + } + } + + /* query current executable filename and application type */ + { + CHAR szName[CCHMAXPATH]; + PPIB ppib; + PTIB ptib; + APIRET rc; + rc = DosGetInfoBlocks(&ptib, &ppib); + rc = DosQueryModuleName(ppib->pib_hmte, sizeof(szName), szName); + DosQueryAppType( (PCSZ)szName, &nOwnAppType ); + } + + /* combination of flags WAIT and DETACHED not supported */ + if( (Options & osl_Process_DETACHED) && (Options & osl_Process_WAIT) ) + Options &= !osl_Process_DETACHED; + + /* start in same session if possible and detached flag not set */ + if( ((nAppType & 0x00000007) == (nOwnAppType & 0x00000007)) +/* && ((Options & osl_Process_DETACHED) == 0) */ ) + { + CHAR szbuf[CCHMAXPATH]; + + /* calculate needed space for arguments */ + n = strlen( pszImageName ) + 1; + if( pszArguments ) + for (i = first; pszArguments[i] != NULL; i++) + n += strlen(pszArguments[i]) + 1; + + /* allocate space for arguments */ + args = (sal_Char*)malloc(n + 1); + pStr = args; + + /* add program name as first string to arguments */ + memcpy(pStr, pszImageName, strlen( pszImageName ) ); + pStr += strlen( pszImageName ); + *pStr++ = '\0'; + + /* add given strings to arguments */ + if( pszArguments ) + for (i = first; pszArguments[i] != NULL; i++) + { + memcpy(pStr, pszArguments[i], strlen( pszArguments[i] ) ); + pStr += strlen( pszArguments[i] ); + if (pszArguments[i+1] != NULL) + *pStr++ = ' '; + } + + /* set end marker for arguments */ + *pStr++ = '\0'; + *pStr = '\0'; + + OSL_TRACE( "osl_executeProcess with DosExecPgm (args: %s)\n", args ); + + /* calculate needed space for environment: since enviroment var search + is a linear scan of the current enviroment, we place new variables + before existing ones; so the child will find new definitions before + olders; this doesn't require us to replace existing vars */ + // existing enviroment size + n = 0; + p = environ; + while( *p) + { + int l = strlen( *p); + n += l + 1; + p++; + } + // new env size (if exists) + if( pszEnvironments ) + { + for (i = 0; pszEnvironments[i] != NULL; i++) + n += strlen(pszEnvironments[i]) + 1; + } + /* allocate space for environment */ + envs = (sal_Char*)malloc(n + 1); + pStr = envs; + + // add new vars + if( pszEnvironments ) + { + /* add given strings to environment */ + for (i = 0; pszEnvironments[i] != NULL; i++) + { + memcpy(pStr, pszEnvironments[i], strlen( pszEnvironments[i] ) ); + pStr += strlen( pszEnvironments[i] ); + *pStr++ = '\0'; + } + } + // add existing vars + p = environ; + while( *p) + { + memcpy(pStr, *p, strlen( *p ) ); + pStr += strlen( *p ); + *pStr++ = '\0'; + p++; + } + /* set end marker for environment */ + *pStr = '\0'; + + + if(Options & osl_Process_DETACHED) + { + rc = DosExecPgm( szbuf, sizeof( szbuf ), EXEC_BACKGROUND, + (PSZ) args, (PSZ) envs, &resultCode, (PSZ) pszImageName ); + } + else + { + rc = DosExecPgm( szbuf, sizeof( szbuf ), EXEC_ASYNCRESULT, + (PSZ) args, (PSZ) envs, &resultCode, (PSZ) pszImageName ); + } + + pidProcess = resultCode.codeTerminate; + + /* cleanup */ + free(envs); + free(args); + + /* error handling */ + if( rc != NO_ERROR ) + return osl_Process_E_Unknown; + } + + else + { + STARTDATA SData = { 0 }; + UCHAR achObjBuf[ 256 ] = { 0 }; + + /* combine arguments separated by spaces */ + if( pszArguments ) + { + for (i = first; pszArguments[i] != NULL; i++) + n += strlen(pszArguments[i]) + 1; + // YD DosStartSession requires low-mem buffers! + args = (sal_Char*)_tmalloc(n); + *args = '\0'; + for (i = first; pszArguments[i] != NULL; i++) + { + strcat(args, pszArguments[i]); + strcat(args, " "); + } + } + else + args = NULL; + + /* combine environment separated by NULL */ + if( pszEnvironments ) + { + for (i = 0; pszEnvironments[i] != NULL; i++) + n += strlen(pszEnvironments[i]) + 1; + // YD DosStartSession requires low-mem buffers! + envs = (sal_Char*)_tmalloc(n + 1); + pStr = (sal_Char*)envs; + for (i = 0; pszEnvironments[i] != NULL; i++) + { + memcpy(pStr, pszEnvironments[i], strlen( pszEnvironments[i] ) ); + pStr += strlen( pszEnvironments[i] ); + *pStr = '\0'; + pStr++; + } + *pStr = '\0'; + } + else + envs = NULL; + + /* initialize data structure */ + memset( &SData, 0, sizeof( STARTDATA ) ); + SData.Length = sizeof(STARTDATA); + + OSL_TRACE( "osl_executeProcess with DosStartSession (args: %s)\n", args ); + + /* OS/2 Application ? */ + if(nAppType & 0x00000007) + { + + /* inherit options from parent */ + SData.InheritOpt = SSF_INHERTOPT_PARENT; + + switch (Options & (osl_Process_NORMAL | osl_Process_MINIMIZED | + osl_Process_MAXIMIZED | osl_Process_FULLSCREEN)) + { + case osl_Process_MINIMIZED: + SData.SessionType = SSF_TYPE_DEFAULT; + SData.PgmControl |= SSF_CONTROL_MINIMIZE; + break; + + case osl_Process_MAXIMIZED: + SData.SessionType = SSF_TYPE_DEFAULT; + SData.PgmControl |= SSF_CONTROL_MAXIMIZE; + break; + + case osl_Process_FULLSCREEN: + SData.SessionType = SSF_TYPE_FULLSCREEN; + break; + + default: + SData.SessionType = SSF_TYPE_DEFAULT; + } /* switch */ + } + + + if( Options & osl_Process_DETACHED ) + { + /* start an independent session */ + SData.Related = SSF_RELATED_INDEPENDENT; + SData.TermQ = NULL; + } + else + { + /* start a child session and set Termination Queue */ + SData.Related = SSF_RELATED_CHILD; + + if(! bInitSessionTerm) + bInitSessionTerm = InitSessionTerm(); + + SData.TermQ = (BYTE*) SessionTermQueueName; + } + + SData.FgBg = SSF_FGBG_FORE; /* start session in foreground */ + SData.TraceOpt = SSF_TRACEOPT_NONE; /* No trace */ + + SData.PgmTitle = NULL; + SData.PgmInputs = (BYTE*)args; + SData.PgmName = (PSZ) pszImageName; + SData.Environment = (BYTE*)envs; + + if( Options & osl_Process_HIDDEN ) + SData.PgmControl |= SSF_CONTROL_INVISIBLE; + else + SData.PgmControl |= SSF_CONTROL_VISIBLE; + + SData.ObjectBuffer = (PSZ) achObjBuf; + SData.ObjectBuffLen = (ULONG) sizeof(achObjBuf); + + + /* Start the session */ + rc = DosStartSession( &SData, &ulSessID, &pidProcess ); + + /* ignore error "session started in background" */ + if( rc == ERROR_SMG_START_IN_BACKGROUND ) + rc = NO_ERROR; + + + if(envs) + _tfree(envs); + if(args) + _tfree(args); + + if( rc != NO_ERROR ) + return osl_Process_E_Unknown; + + } /* else */ + + + /* restore current disk */ + if(nCurrentDisk) + { + DosSetDefaultDisk(nCurrentDisk); + } + + /* restore current drive information */ + if(*currentDir) + { + DosSetCurrentDir((PCSZ)currentDir); + } + + /* allocate intern process structure and store child process ID */ + pProcImpl = (oslProcessImpl*)malloc(sizeof(oslProcessImpl)); + pProcImpl->pProcess = pidProcess; + pProcImpl->nSessionID = ulSessID; + + pProcImpl->bResultCodeValid = FALSE; + + if( Options & osl_Process_WAIT ) + osl_joinProcess(pProcImpl); + + *pProcess = (oslProcess)pProcImpl; + + if( rc == NO_ERROR ) + return osl_Process_E_None; + else + + return osl_Process_E_Unknown; +} + +/*----------------------------------------------------------------------------*/ + +oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process) +{ + if (Process == NULL) + return osl_Process_E_Unknown; + + /* Stop the session */ + DosStopSession( STOP_SESSION_SPECIFIED, ((oslProcessImpl*)Process)->nSessionID ); + + return osl_Process_E_None; +} + +/*----------------------------------------------------------------------------*/ + +oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident) +{ + HANDLE hProcess; + oslProcessImpl* pProcImpl; + + /* check, if given PID is a valid process */ + if (FALSE) + { + pProcImpl = (oslProcessImpl*)malloc(sizeof(oslProcessImpl)); +/* + pProcImpl->pProcess = pidProcess; + pProcImpl->nSessionID = ulSessID; +*/ + } + else + pProcImpl = NULL; + + return (pProcImpl); +} + +/*----------------------------------------------------------------------------*/ + +void SAL_CALL osl_freeProcessHandle(oslProcess Process) +{ + /* free intern process structure */ + if (Process != NULL) + free((oslProcessImpl*)Process); +} + +/*----------------------------------------------------------------------------*/ + +oslProcessError SAL_CALL osl_joinProcess(oslProcess Process) +{ + oslProcessImpl* pProcImpl = (oslProcessImpl*) Process; + APIRET rc; + + if (Process == NULL) + return osl_Process_E_Unknown; + + /* process of same session ? */ + if( pProcImpl->nSessionID == 0 ) + { + RESULTCODES resultCode; + PID pidEnded; + + rc = DosWaitChild( DCWA_PROCESS, DCWW_WAIT, &resultCode, + &pidEnded, pProcImpl->pProcess ); + + if( rc == NO_ERROR ) + { + pProcImpl->nResultCode = resultCode.codeResult; + pProcImpl->bResultCodeValid = TRUE; + + return osl_Process_E_None; + } + } + else + { + ULONG pcbData, ulElement = 0; + REQUESTDATA rdData; + BYTE bPriority; + struct { + USHORT SessionID; + USHORT ReturnValue; + } *pvBuffer; + + /* search/wait for the correct entry in termination queue */ + while( ( rc = DosPeekQueue( SessionTermQueue, &rdData, &pcbData, + (PPVOID) &pvBuffer, &ulElement, DCWW_WAIT, + &bPriority, NULLHANDLE )) == NO_ERROR ) + { + + if( pvBuffer->SessionID == pProcImpl->nSessionID ) + { + pProcImpl->nResultCode = pvBuffer->ReturnValue; + pProcImpl->bResultCodeValid = TRUE; + + /* remove item from queue */ + rc = DosReadQueue( SessionTermQueue, &rdData, &pcbData, + (PPVOID)&pvBuffer, ulElement, DCWW_WAIT, + &bPriority, NULLHANDLE ); + + if( rc == NO_ERROR ) + return osl_Process_E_None; + else + return osl_Process_E_Unknown; + } + } /* while */ + } + return osl_Process_E_Unknown; +} + +/***************************************************************************/ + +//YD FIXME incomplete! +oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout) +{ + return osl_joinProcess( Process); +} + +/*----------------------------------------------------------------------------*/ + +oslProcessError SAL_CALL osl_getCommandArgs( sal_Char* pszBuffer, sal_uInt32 Max) +{ + + static int CmdLen = -1; + static sal_Char CmdLine[_MAX_CMD]; + + OSL_ASSERT(pszBuffer); + OSL_ASSERT(Max > 1); + + /* Query commandline during first call of function only */ + if (CmdLen < 0) + { + sal_Bool bEscaped = sal_False; + sal_Bool bSeparated = sal_True; + sal_Char* pszBufferOrg = pszBuffer; + sal_Char* pszCmdLine; + + /* get pointer to commandline */ + { + PTIB pptib = NULL; + PPIB pppib = NULL; + + DosGetInfoBlocks(&pptib, &pppib); + pszCmdLine = pppib->pib_pchcmd; + } + + /* skip first string */ + while( *pszCmdLine ) + pszCmdLine++; + + /* concatenate commandline arguments for the given string */ + Max -= 2; + while ( !((*pszCmdLine == '\0') && (*(pszCmdLine + 1) == '\0')) && (Max > 0)) + { + /* + * C-Runtime expects char to be unsigned and so to be + * preceeded with 00 instead of FF when converting to int + */ + int n = *((unsigned char *) pszCmdLine); + if (! (isspace(n) || (*pszCmdLine == '\0')) ) + { + if (*pszCmdLine == '"') + { + if (*(pszCmdLine + 1) != '"') + bEscaped = ! bEscaped; + else + { + pszCmdLine++; + *pszBuffer++ = *pszCmdLine; + Max--; + } + } + else + { + *pszBuffer++ = *pszCmdLine; + Max--; + } + bSeparated = sal_False; + } + else + { + if (bEscaped) + *pszBuffer++ = *pszCmdLine; + else + if (! bSeparated) + { + *pszBuffer++ = '\0'; + bSeparated = sal_True; + } + Max--; + } + + pszCmdLine++; + } + + *pszBuffer++ = '\0'; + *pszBuffer++ = '\0'; + + /* restore pointer and save commandline for next query */ + CmdLen = pszBuffer - pszBufferOrg; + pszBuffer = pszBufferOrg; + memcpy( CmdLine, pszBuffer, CmdLen ); + } + else + memcpy( pszBuffer, CmdLine, CmdLen ); + + OSL_TRACE( "osl_getCommandArgs (args: %s)\n", pszBuffer ); + + return osl_Process_E_None; +} + +/*----------------------------------------------------------------------------*/ + +oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, + oslProcessInfo* pInfo) +{ + if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo))) + return osl_Process_E_Unknown; + + pInfo->Fields = 0; + + if (Fields & osl_Process_IDENTIFIER) + { + if( Process == NULL ) + { + PTIB pptib = NULL; + PPIB pppib = NULL; + + DosGetInfoBlocks( &pptib, &pppib ); + pInfo->Ident = pppib->pib_ulpid; + } + else + pInfo->Ident = ((oslProcessImpl*)Process)->pProcess; + + pInfo->Fields |= osl_Process_IDENTIFIER; + } + + if (Fields & osl_Process_EXITCODE) + { + oslProcessImpl* pProcImpl = (oslProcessImpl*) Process; + + if( pProcImpl->bResultCodeValid ) + { + pInfo->Code = pProcImpl->nResultCode; + pInfo->Fields |= osl_Process_EXITCODE; + } + else + { + APIRET rc; + + if( pProcImpl->nSessionID == 0 ) + { + RESULTCODES resultCode; + PID pidEnded; + + rc = DosWaitChild( DCWA_PROCESS, DCWW_WAIT, &resultCode, + &pidEnded, pProcImpl->pProcess ); + + if( rc == NO_ERROR ) + { + pProcImpl->nResultCode = resultCode.codeResult; + pProcImpl->bResultCodeValid = TRUE; + + pInfo->Code = pProcImpl->nResultCode; + pInfo->Fields |= osl_Process_EXITCODE; + + return osl_Process_E_None; + } + } + else + { + ULONG pcbData, ulElement = 0; + REQUESTDATA rdData; + BYTE bPriority; + struct { + USHORT SessionID; + USHORT ReturnValue; + } *pvBuffer; + + /* search/wait for the correct entry in termination queue */ + while( ( rc = DosPeekQueue( SessionTermQueue, &rdData, &pcbData, + (PPVOID) &pvBuffer, &ulElement, DCWW_WAIT, + &bPriority, NULLHANDLE )) == NO_ERROR ) + { + + if( pvBuffer->SessionID == pProcImpl->nSessionID ) + { + pProcImpl->nResultCode = pvBuffer->ReturnValue; + pProcImpl->bResultCodeValid = TRUE; + + pInfo->Code = pProcImpl->nResultCode; + pInfo->Fields |= osl_Process_EXITCODE; + + /* remove item from queue */ + rc = DosReadQueue( SessionTermQueue, &rdData, &pcbData, + (PPVOID)&pvBuffer, ulElement, DCWW_WAIT, + &bPriority, NULLHANDLE ); + + break; + } + } + } + } + } + + if (Fields & osl_Process_HEAPUSAGE) + { + } + if (Fields & osl_Process_CPUTIMES) + { + } + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; +} diff --git a/sal/osl/os2/process_impl.cxx b/sal/osl/os2/process_impl.cxx new file mode 100644 index 000000000000..27b12bbe0f6a --- /dev/null +++ b/sal/osl/os2/process_impl.cxx @@ -0,0 +1,371 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#define INCL_DOS +#include <os2.h> + +#include "osl/process.h" +#include <osl/mutex.h> + +#ifndef INCLUDED_LIMITS_H +#include <limits.h> +#define INCLUDED_LIMITS_H +#endif + +#ifndef INCLUDED_PTHREAD_H +#include <pthread.h> +#define INCLUDED_PTHREAD_H +#endif + +#ifndef INCLUDED_STDLIB_H +#include <stdlib.h> +#define INCLUDED_STDLIB_H +#endif + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif +#include "osl/diagnose.h" +#include <osl/file.h> +#include "osl/module.h" +#include "osl/thread.h" +#include "rtl/ustring.hxx" + +#ifndef _OSL_FILE_PATH_HELPER_H_ +#include "file_path_helper.h" +#endif + +#ifndef _OSL_UUNXAPI_H_ +#include "uunxapi.h" +#endif + +/*************************************** + osl_bootstrap_getExecutableFile_Impl(). + + @internal + @see rtl_bootstrap + @see #i37371# + + **************************************/ + +extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C(); + + +oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C() +{ + oslProcessError result = osl_Process_E_NotFound; + CHAR szName[CCHMAXPATH]; + PPIB ppib; + PTIB ptib; + APIRET rc; + + rc = DosGetInfoBlocks(&ptib, &ppib); + rc = DosQueryModuleName(ppib->pib_hmte, sizeof(szName), szName); + + if (rc == 0) + { + rtl_uString * pAbsPath = 0; + + rtl_string2UString( + &pAbsPath, + szName, strlen(szName), osl_getThreadTextEncoding(), + OSTRING_TO_OUSTRING_CVTFLAGS); + + if (pAbsPath) + { + /* Convert from path to url. */ + if (osl_getFileURLFromSystemPath (pAbsPath, ppFileURL) == osl_File_E_None) + { + /* Success. */ + result = osl_Process_E_None; + } + rtl_uString_release (pAbsPath); + } + } + + return (result); +} + +/*************************************** + CommandArgs_Impl. + **************************************/ +struct CommandArgs_Impl +{ + oslMutex m_mutex; + sal_uInt32 m_nCount; + rtl_uString ** m_ppArgs; +}; + +static struct CommandArgs_Impl g_command_args = +{ + osl_createMutex(), + 0, + 0 +}; + +/*************************************** + osl_getExecutableFile(). + **************************************/ +oslProcessError SAL_CALL osl_getExecutableFile (rtl_uString ** ppustrFile) +{ + oslProcessError result = osl_Process_E_NotFound; + + osl_acquireMutex(g_command_args.m_mutex); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > 0) + { + /* CommandArgs set. Obtain argv[0]. */ + rtl_uString_assign (ppustrFile, g_command_args.m_ppArgs[0]); + result = osl_Process_E_None; + } + osl_releaseMutex(g_command_args.m_mutex); + + return (result); +} + +/*************************************** + osl_getCommandArgCount(). + **************************************/ +sal_uInt32 SAL_CALL osl_getCommandArgCount (void) +{ + sal_uInt32 result = 0; + + osl_acquireMutex(g_command_args.m_mutex); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > 0) + result = g_command_args.m_nCount - 1; + osl_releaseMutex(g_command_args.m_mutex); + + return (result); +} + +/*************************************** + osl_getCommandArg(). + **************************************/ +oslProcessError SAL_CALL osl_getCommandArg (sal_uInt32 nArg, rtl_uString ** strCommandArg) +{ + oslProcessError result = osl_Process_E_NotFound; + + osl_acquireMutex(g_command_args.m_mutex); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > (nArg + 1)) + { + rtl_uString_assign (strCommandArg, g_command_args.m_ppArgs[nArg + 1]); + result = osl_Process_E_None; + } + osl_releaseMutex(g_command_args.m_mutex); + + return (result); +} + +/*************************************** + osl_setCommandArgs(). + **************************************/ +void SAL_CALL osl_setCommandArgs (int argc, char ** argv) +{ + OSL_ASSERT(argc > 0); + osl_acquireMutex(g_command_args.m_mutex); + OSL_ENSURE (g_command_args.m_nCount == 0, "osl_setCommandArgs(): CommandArgs already set."); + if (g_command_args.m_nCount == 0) + { + rtl_uString** ppArgs = (rtl_uString**)rtl_allocateZeroMemory (argc * sizeof(rtl_uString*)); + if (ppArgs != 0) + { + rtl_TextEncoding encoding = osl_getThreadTextEncoding(); + for (int i = 0; i < argc; i++) + { + rtl_string2UString ( + &(ppArgs[i]), + argv[i], rtl_str_getLength (argv[i]), encoding, + OSTRING_TO_OUSTRING_CVTFLAGS); + } + if (ppArgs[0] != 0) + { + /* see @ osl_getExecutableFile(). */ + if (rtl_ustr_indexOfChar (rtl_uString_getStr(ppArgs[0]), sal_Unicode('/')) == -1) + { + const rtl::OUString PATH (RTL_CONSTASCII_USTRINGPARAM("PATH")); + + rtl_uString * pSearchPath = 0; + osl_getEnvironment (PATH.pData, &pSearchPath); + if (pSearchPath) + { + rtl_uString * pSearchResult = 0; + osl_searchPath (ppArgs[0], pSearchPath, &pSearchResult); + if (pSearchResult) + { + rtl_uString_assign (&(ppArgs[0]), pSearchResult); + rtl_uString_release (pSearchResult); + } + rtl_uString_release (pSearchPath); + } + } + + rtl_uString * pArg0 = 0; + if (realpath_u (ppArgs[0], &pArg0)) + { + osl_getFileURLFromSystemPath (pArg0, &(ppArgs[0])); + rtl_uString_release (pArg0); + } + } + g_command_args.m_nCount = argc; + g_command_args.m_ppArgs = ppArgs; + } + } + osl_releaseMutex(g_command_args.m_mutex); + +} + +/*************************************** + osl_getEnvironment(). + **************************************/ +oslProcessError SAL_CALL osl_getEnvironment(rtl_uString* pustrEnvVar, rtl_uString** ppustrValue) +{ + oslProcessError result = osl_Process_E_NotFound; + rtl_TextEncoding encoding = osl_getThreadTextEncoding(); + rtl_String* pstr_env_var = 0; + + OSL_PRECOND(pustrEnvVar, "osl_getEnvironment(): Invalid parameter"); + OSL_PRECOND(ppustrValue, "osl_getEnvironment(): Invalid parameter"); + + rtl_uString2String( + &pstr_env_var, + rtl_uString_getStr(pustrEnvVar), rtl_uString_getLength(pustrEnvVar), encoding, + OUSTRING_TO_OSTRING_CVTFLAGS); + if (pstr_env_var != 0) + { + const char* p_env_var = getenv (rtl_string_getStr (pstr_env_var)); + if (p_env_var != 0) + { + rtl_string2UString( + ppustrValue, + p_env_var, strlen(p_env_var), encoding, + OSTRING_TO_OUSTRING_CVTFLAGS); + OSL_ASSERT(*ppustrValue != NULL); + + result = osl_Process_E_None; + } + rtl_string_release(pstr_env_var); + } + + return (result); +} + +/*************************************** + osl_getProcessWorkingDir(). + **************************************/ +oslProcessError SAL_CALL osl_getProcessWorkingDir(rtl_uString **ppustrWorkingDir) +{ + oslProcessError result = osl_Process_E_Unknown; + char buffer[PATH_MAX]; + + OSL_PRECOND(ppustrWorkingDir, "osl_getProcessWorkingDir(): Invalid parameter"); + + if (getcwd (buffer, sizeof(buffer)) != 0) + { + rtl_uString* ustrTmp = 0; + + rtl_string2UString( + &ustrTmp, + buffer, strlen(buffer), osl_getThreadTextEncoding(), + OSTRING_TO_OUSTRING_CVTFLAGS); + if (ustrTmp != 0) + { + if (osl_getFileURLFromSystemPath (ustrTmp, ppustrWorkingDir) == osl_File_E_None) + result = osl_Process_E_None; + rtl_uString_release (ustrTmp); + } + } + + return (result); +} + +/****************************************************************************** + * + * new functions to set/return the current process locale + * + *****************************************************************************/ + +struct ProcessLocale_Impl +{ + oslMutex m_mutex; + rtl_Locale * m_pLocale; +}; + +static struct ProcessLocale_Impl g_process_locale = +{ + osl_createMutex(), + 0 +}; + +extern "C" void _imp_getProcessLocale( rtl_Locale ** ); +extern "C" int _imp_setProcessLocale( rtl_Locale * ); + +/********************************************** + osl_getProcessLocale(). + *********************************************/ +oslProcessError SAL_CALL osl_getProcessLocale( rtl_Locale ** ppLocale ) +{ + OSL_PRECOND(ppLocale, "osl_getProcessLocale(): Invalid parameter."); + + osl_acquireMutex(g_process_locale.m_mutex); + + if (g_process_locale.m_pLocale == 0) + _imp_getProcessLocale (&(g_process_locale.m_pLocale)); + *ppLocale = g_process_locale.m_pLocale; + + osl_releaseMutex(g_process_locale.m_mutex); + + return (osl_Process_E_None); +} + +/********************************************** + osl_setProcessLocale(). + *********************************************/ +oslProcessError SAL_CALL osl_setProcessLocale( rtl_Locale * pLocale ) +{ + oslProcessError result = osl_Process_E_Unknown; + + OSL_PRECOND(pLocale, "osl_setProcessLocale(): Invalid parameter."); + + osl_acquireMutex(g_process_locale.m_mutex); + if (_imp_setProcessLocale (pLocale) == 0) + { + g_process_locale.m_pLocale = pLocale; + result = osl_Process_E_None; + } + osl_releaseMutex(g_process_locale.m_mutex); + + return (result); +} + diff --git a/sal/osl/os2/procimpl.h b/sal/osl/os2/procimpl.h new file mode 100644 index 000000000000..5ff7a9f36b91 --- /dev/null +++ b/sal/osl/os2/procimpl.h @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_PROCIMPL_H_ +#define _OSL_PROCIMPL_H_ + + +#include <osl/process.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _oslProcessImpl { + + PID pProcess; + sal_uInt32 nSessionID; + sal_uInt32 nResultCode; + BOOL bResultCodeValid; +} oslProcessImpl; + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/sal/osl/os2/profile.c b/sal/osl/os2/profile.c new file mode 100644 index 000000000000..d9d166d0e091 --- /dev/null +++ b/sal/osl/os2/profile.c @@ -0,0 +1,2295 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +// YD #define min(a,b) (((a) < (b)) ? (a) : (b)) + +#include <osl/security.h> +#include <osl/diagnose.h> +#include <osl/profile.h> +#include <osl/process.h> +#include <osl/thread.h> +#include <osl/file.h> + +#define LINES_INI 32 +#define LINES_ADD 10 +#define SECTIONS_INI 5 +#define SECTIONS_ADD 3 +#define ENTRIES_INI 5 +#define ENTRIES_ADD 3 + + +#define STR_INI_EXTENSION ".ini" +#define STR_INI_METAHOME "?~" +#define STR_INI_METASYS "?$" +#define STR_INI_METACFG "?^" +#define STR_INI_METAINS "?#" + +#define STR_INI_BOOLYES "yes" +#define STR_INI_BOOLON "on" +#define STR_INI_BOOLONE "1" +#define STR_INI_BOOLNO "no" +#define STR_INI_BOOLOFF "off" +#define STR_INI_BOOLZERO "0" + +#define FLG_USER 0x00FF +#define FLG_AUTOOPEN 0x0100 +#define FLG_MODIFIED 0x0200 + +#define SVERSION_LOCATION STR_INI_METACFG +#define SVERSION_FALLBACK STR_INI_METASYS +#define SVERSION_NAME "sversion" +#define SVERSION_SECTION "Versions" +#define SVERSION_SOFFICE "StarOffice" +#define SVERSION_PROFILE "soffice.ini" +#define SVERSION_OPTION "userid:" +#define SVERSION_DIRS { "bin", "program" } +#define SVERSION_USER "user" + +#define _BUILD_STR_(n) # n +#define BUILD_STR(n) _BUILD_STR_(n) + +/* implemented in file.c */ +extern oslFileError FileURLToPath( char *, size_t, rtl_uString* ); + +/*****************************************************************************/ +/* Data Type Definition */ +/*****************************************************************************/ + +typedef struct _osl_TStamp +{ + FDATE m_Date; + FTIME m_Time; +} osl_TStamp; + +typedef enum _osl_TLockMode +{ + un_lock, read_lock, write_lock +} osl_TLockMode; + +typedef struct _osl_TFile +{ + HFILE m_Handle; +/* + sal_Char* m_pReadPtr; + sal_Char m_ReadBuf[512]; + sal_Char* m_pWritePtr; + sal_Char m_WriteBuf[512]; +*/ + sal_Char* m_pReadPtr; + sal_Char m_ReadBuf[512]; +/* sal_Char* m_pWritePtr; */ +/* sal_Char m_WriteBuf[512]; */ + sal_Char* m_pWriteBuf; + sal_uInt32 m_nWriteBufLen; + sal_uInt32 m_nWriteBufFree; +} osl_TFile; + +typedef struct _osl_TProfileEntry +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; +} osl_TProfileEntry; + +typedef struct _osl_TProfileSection +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; + sal_uInt32 m_NoEntries; + sal_uInt32 m_MaxEntries; + osl_TProfileEntry* m_Entries; +} osl_TProfileSection; + + +/* + Profile-data structure hidden behind oslProfile: +*/ +typedef struct _osl_TProfileImpl +{ + sal_uInt32 m_Flags; + osl_TFile* m_pFile; + osl_TStamp m_Stamp; + //sal_Char m_Filename[_MAX_PATH + 1]; + sal_uInt32 m_NoLines; + sal_uInt32 m_MaxLines; + sal_uInt32 m_NoSections; + sal_uInt32 m_MaxSections; + sal_Char** m_Lines; + rtl_uString *m_strFileName; + osl_TProfileSection* m_Sections; + HINI m_hIni; +} osl_TProfileImpl; + + +/*****************************************************************************/ +/* Static Module Function Declarations */ +/*****************************************************************************/ + +//static osl_TFile* openFile(rtl_uString* pszFilename, sal_Bool bWriteable); +//static osl_TStamp closeFile(osl_TFile* pFile); +static osl_TFile* openFileImpl(rtl_uString * strFileName, oslProfileOption ProfileFlags ); +static osl_TStamp closeFileImpl(osl_TFile* pFile); +static sal_Bool lockFile(const osl_TFile* pFile, osl_TLockMode eMode); +static sal_Bool rewindFile(osl_TFile* pFile, sal_Bool bTruncate); +static osl_TStamp getFileStamp(osl_TFile* pFile); + +static sal_Bool getLine(osl_TFile* pFile, const sal_Char *pszLine, int MaxLen); +static sal_Bool putLine(osl_TFile* pFile, const sal_Char *pszLine); +static const sal_Char* stripBlanks(const sal_Char* String, sal_uInt32* pLen); +static const sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line); +static const sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo); +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo); +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + const sal_Char* Entry, sal_uInt32 Len); +static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, const sal_Char* Entry, sal_uInt32 Len); +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry); +static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len); +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection); +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section, + const sal_Char* Entry, sal_uInt32 *pNoEntry); +static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile); +static sal_Bool storeProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile, sal_Bool bCleanup); +static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable); +static sal_Bool releaseProfile(osl_TProfileImpl* pProfile); +static sal_Bool lookupProfile(const sal_Char *pszPath, const sal_Char *pszFile, sal_Char *pPath); + + +static sal_Bool SAL_CALL osl_getProfileName(rtl_uString* strPath, rtl_uString* strName, rtl_uString** strProfileName); + +sal_Bool SAL_CALL osl_getFullPath(rtl_uString* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen) +{ + return NO_ERROR == DosQueryPathInfo( (PCSZ)pszFilename, FIL_QUERYFULLNAME, pszPath, MaxLen); +} + + + +/*****************************************************************************/ +/* Exported Module Functions */ +/*****************************************************************************/ + +oslProfile SAL_CALL osl_openProfile(rtl_uString *strProfileName, sal_uInt32 Flags) +{ + osl_TFile* pFile; + osl_TProfileImpl* pProfile; + rtl_uString *FileName=NULL; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_openProfile\n"); +#endif + OSL_VERIFY(strProfileName); + +/* if (rtl_uString_getLength(strProfileName) == 0 ) + { + OSL_VERIFY(osl_getProfileName(NULL, NULL, &FileName)); + } + else +*/ + { + rtl_uString_assign(&FileName, strProfileName); + } + + osl_getSystemPathFromFileURL(FileName, &FileName); + +#ifdef DEBUG_OSL_PROFILE + Flags=osl_Profile_FLUSHWRITE; + + // OSL_TRACE("opening '%s'\n",FileName); + if ( Flags == osl_Profile_DEFAULT ) + { + OSL_TRACE("with osl_Profile_DEFAULT \n"); + } + if ( Flags & osl_Profile_SYSTEM ) + { + OSL_TRACE("with osl_Profile_SYSTEM \n"); + } + if ( Flags & osl_Profile_READLOCK ) + { + OSL_TRACE("with osl_Profile_READLOCK \n"); + } + if ( Flags & osl_Profile_WRITELOCK ) + { + OSL_TRACE("with osl_Profile_WRITELOCK \n"); + } +/* if ( Flags & osl_Profile_READWRITE ) */ +/* { */ +/* OSL_TRACE("with osl_Profile_READWRITE \n"); */ +/* } */ + if ( Flags & osl_Profile_FLUSHWRITE ) + { + OSL_TRACE("with osl_Profile_FLUSHWRITE \n"); + } +#endif + + if ((! (Flags & osl_Profile_SYSTEM)) && + ((pFile = openFileImpl(FileName, (Flags & osl_Profile_WRITELOCK) ? sal_True : sal_False)) == NULL)) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_openProfile [not opened]\n"); +#endif + if( FileName) + rtl_uString_release( FileName); + + return (NULL); + } + + pProfile = (osl_TProfileImpl*)calloc(1, sizeof(osl_TProfileImpl)); + + pProfile->m_Flags = Flags & FLG_USER; + osl_getSystemPathFromFileURL(strProfileName, &pProfile->m_strFileName); +// rtl_uString_assign(&pProfile->m_strFileName, strProfileName); + + if (Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK)) + pProfile->m_pFile = pFile; + + pProfile->m_Stamp = getFileStamp(pFile); + + loadProfile(pFile, pProfile); + + if (pProfile->m_pFile == NULL) + closeFileImpl(pFile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_openProfile [ok]\n"); +#endif + if( FileName) + rtl_uString_release( FileName); + + return pProfile; +} + +sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_closeProfile\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [profile==0]\n"); +#endif + return sal_False; + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + pProfile = acquireProfile(Profile,sal_True); + + if ( pProfile != 0 ) + { + if ( !( pProfile->m_Flags & osl_Profile_READLOCK ) && ( pProfile->m_Flags & FLG_MODIFIED ) ) + { +/* if (pProfile->m_pFile == NULL) */ +/* pProfile->m_pFile = openFileImpl(pProfile->m_Filename, sal_True); */ + + storeProfile(pProfile->m_pFile, pProfile, sal_False); + } + } + else + { + pProfile = acquireProfile(Profile,sal_False); + } + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [pProfile==0]\n"); +#endif + return sal_False; + } + + if (pProfile->m_pFile != NULL) + closeFileImpl(pProfile->m_pFile); + } + + pProfile->m_pFile = NULL; + rtl_uString_release(pProfile->m_strFileName); + pProfile->m_strFileName = NULL; + + /* release whole profile data types memory */ + if ( pProfile->m_NoLines > 0) + { + unsigned int index=0; + if ( pProfile->m_Lines != 0 ) + { + for ( index = 0 ; index < pProfile->m_NoLines ; ++index) + { + if ( pProfile->m_Lines[index] != 0 ) + { + free(pProfile->m_Lines[index]); + } + } + free(pProfile->m_Lines); + } + if ( pProfile->m_Sections != 0 ) + { + /*osl_TProfileSection* pSections=pProfile->m_Sections;*/ + for ( index = 0 ; index < pProfile->m_NoSections ; ++index ) + { + if ( pProfile->m_Sections[index].m_Entries != 0 ) + { + free(pProfile->m_Sections[index].m_Entries); + } + } + free(pProfile->m_Sections); + } + + } + free(pProfile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [ok]\n"); +#endif + return (sal_True); +} + +sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*) Profile; + osl_TFile* pFile; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_flushProfile()\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [pProfile == 0]\n"); +#endif + return sal_False; + } + + pFile = pProfile->m_pFile; + if ( !( pFile != 0 && pFile->m_Handle >= 0 ) ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [invalid file]\n"); +#endif + return sal_False; + } + + if ( pProfile->m_Flags & FLG_MODIFIED ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("swapping to storeprofile\n"); +#endif + bRet = storeProfile(pFile,pProfile,sal_False); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [ok]\n"); +#endif + return bRet; +} + +sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Char* pszString, sal_uInt32 MaxLen, + const sal_Char* pszDefault) +{ + sal_uInt32 NoEntry; + const sal_Char* pStr = 0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileString\n"); +#endif + + pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pProfile==0]\n"); +#endif + + + return (sal_False); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) && + (NoEntry < pSec->m_NoEntries) && + ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line], + '=')) != NULL)) + pStr++; + else + pStr = pszDefault; + + if ( pStr != 0 ) + { + pStr = stripBlanks(pStr, NULL); + MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr); + pStr = stripBlanks(pStr, &MaxLen); + strncpy(pszString, pStr, MaxLen); + pszString[MaxLen] = '\0'; + } + } + else + PrfQueryProfileString(pProfile->m_hIni, (PCSZ)pszSection, + (PCSZ)pszEntry, (PCSZ)pszDefault, + pszString, MaxLen); + + releaseProfile(pProfile); + + if ( pStr == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pStr==0]\n"); +#endif + + + return (sal_False); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [ok]\n"); +#endif + + return (sal_True); +} + + +sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Bool Default) +{ + sal_Char Line[32]; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileBool\n"); +#endif + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + if ((stricmp(Line, STR_INI_BOOLYES) == 0) || + (stricmp(Line, STR_INI_BOOLON) == 0) || + (stricmp(Line, STR_INI_BOOLONE) == 0)) + Default = sal_True; + else + if ((stricmp(Line, STR_INI_BOOLNO) == 0) || + (stricmp(Line, STR_INI_BOOLOFF) == 0) || + (stricmp(Line, STR_INI_BOOLZERO) == 0)) + Default = sal_False; + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileBool [ok]\n"); +#endif + + return (Default); +} + + +sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_uInt32 FirstId, const sal_Char* Strings[], + sal_uInt32 Default) +{ + sal_uInt32 i; + sal_Char Line[256]; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileIdent\n"); +#endif + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + i = 0; + while (Strings[i] != NULL) + { + if (stricmp(Line, Strings[i]) == 0) + { + Default = i + FirstId; + break; + } + i++; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileIdent [ok]\n"); +#endif + return (Default); +} + + +sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + const sal_Char* pszString) +{ + sal_uInt32 i; + sal_Bool bRet = sal_False; + sal_uInt32 NoEntry; + const sal_Char* pStr; + sal_Char Line[4096]; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileString\n"); +#endif + + pProfile = acquireProfile(Profile, sal_True); + + if (pProfile == NULL) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [pProfile==0]\n"); +#endif + return (sal_False); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == NULL) + { + Line[0] = '\0'; + addLine(pProfile, Line); + + Line[0] = '['; + strcpy(&Line[1], pszSection); + Line[1 + strlen(pszSection)] = ']'; + Line[2 + strlen(pszSection)] = '\0'; + + if (((pStr = addLine(pProfile, Line)) == NULL) || + (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection)))) + { + releaseProfile(pProfile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not added]\n"); +#endif + return (sal_False); + } + + pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1]; + NoEntry = pSec->m_NoEntries; + } + + Line[0] = '\0'; + strcpy(&Line[0], pszEntry); + Line[0 + strlen(pszEntry)] = '='; + strcpy(&Line[1 + strlen(pszEntry)], pszString); + + if (NoEntry >= pSec->m_NoEntries) + { + if (pSec->m_NoEntries > 0) + i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1; + else + i = pSec->m_Line + 1; + + if (((pStr = insertLine(pProfile, Line, i)) == NULL) || + (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry)))) + { + releaseProfile(pProfile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not inserted]\n"); +#endif + return (sal_False); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + else + { + i = pSec->m_Entries[NoEntry].m_Line; + free(pProfile->m_Lines[i]); + pProfile->m_Lines[i] = strdup(Line); + setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry)); + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else + PrfWriteProfileString(pProfile->m_hIni, (PCSZ)pszSection, + (PCSZ)pszEntry, (PCSZ)pszString); + + bRet = releaseProfile(pProfile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [ok]\n"); +#endif + return bRet; +} + + +sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Bool Value) +{ + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileBool\n"); +#endif + + if (Value) + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE); + else + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileBool [ok]\n"); +#endif + + return bRet; +} + + +sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_uInt32 FirstId, const sal_Char* Strings[], + sal_uInt32 Value) +{ + int i, n; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileIdent\n"); +#endif + + for (n = 0; Strings[n] != NULL; n++); + + if ((i = Value - FirstId) >= n) + bRet=sal_False; + else + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileIdent\n"); +#endif + return bRet; +} + + +sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile, + const sal_Char *pszSection, const sal_Char *pszEntry) +{ + sal_uInt32 NoEntry; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_removeProfileEntry\n"); +#endif + + pProfile = acquireProfile(Profile, sal_True); + + if (pProfile == NULL) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [pProfile==0]\n"); +#endif + + + return (sal_False); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) && + (NoEntry < pSec->m_NoEntries)) + { + removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line); + removeEntry(pSec, NoEntry); + if (pSec->m_NoEntries == 0) + { + removeLine(pProfile, pSec->m_Line); + + /* remove any empty separation line */ + if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0')) + removeLine(pProfile, pSec->m_Line - 1); + + removeSection(pProfile, pSec); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else + PrfWriteProfileString(pProfile->m_hIni, (PCSZ)pszSection, (PCSZ)pszEntry, NULL); + + bRet = releaseProfile(pProfile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [ok]\n"); +#endif + return bRet; +} + + +sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile, const sal_Char *pszSection, + sal_Char* pszBuffer, sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + sal_uInt32 NoEntry; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_getProfileSectionEntries\n"); +#endif + + pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [pProfile=0]\n"); +#endif + + + return (0); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != NULL) + { + if (MaxLen != 0) + { + for (i = 0; i < pSec->m_NoEntries; i++) + { + if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len); + n += pSec->m_Entries[i].m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pSec->m_NoEntries; i++) + n += pSec->m_Entries[i].m_Len + 1; + + n += 1; + } + } + else + n = 0; + } + else + n = PrfQueryProfileString(pProfile->m_hIni, (PCSZ)pszSection, NULL, NULL, + pszBuffer, MaxLen ); + + releaseProfile(pProfile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [ok]\n"); +#endif + + return (n); +} + +sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile, sal_Char* pszBuffer, sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + return (0); + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (MaxLen != 0) + { + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if ((n + pSec->m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], + pSec->m_Len); + n += pSec->m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pProfile->m_NoSections; i++) + n += pProfile->m_Sections[i].m_Len + 1; + + n += 1; + } + } + else + n = PrfQueryProfileString(pProfile->m_hIni, NULL, NULL, NULL, + pszBuffer, MaxLen ); + + releaseProfile(pProfile); + + return (n); +} + +#if 0 // YD +sal_Bool SAL_CALL osl_getProfileName(rtl_uString* strPath, rtl_uString* strName, rtl_uString** strProfileName) +{ + sal_Bool bFailed; + sal_Char File[_MAX_PATH]; + sal_Char Path[_MAX_PATH]; + sal_uInt32 nFileLen; + sal_uInt32 nPathLen = 0; + + rtl_uString * strTmp = NULL; + oslFileError nError; + + /* build file name */ + if (strName && strName->length) + { + if(strName->length >= _MAX_PATH) + return sal_False; + + strcpy(File, (char*)strName->buffer); + nFileLen = strName->length; + + if (rtl_ustr_indexOfChar( File, L'.' ) == -1) + { + if (nFileLen + strlen(STR_INI_EXTENSION) >= _MAX_PATH) + return sal_False; + + /* add default extension */ + strcpy(File + nFileLen, STR_INI_EXTENSION); + nFileLen += strlen(STR_INI_EXTENSION); + } + } + else + { + rtl_uString *strProgName = NULL; + sal_Unicode *pProgName; + sal_Int32 nOffset = 0; + sal_Int32 nLen; + sal_Int32 nPos; + + if (osl_getExecutableFile(&strProgName) != osl_Process_E_None) + return sal_False; + + /* remove path and extension from filename */ + pProgName = strProgName->buffer; + nLen = strProgName->length ; + + if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L'/' )) != -1) + nOffset = nPos + 1; + else if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L':' )) != -1) + nOffset = nPos + 1; + + if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L'.' )) != -1 ) + nLen -= 4; + + if ((nFileLen = nLen - nOffset) >= _MAX_PATH) + return sal_False; + + strncpy(File, pProgName + nOffset, nFileLen); + + if (nFileLen + strlen(STR_INI_EXTENSION) >= _MAX_PATH) + return sal_False; + + /* add default extension */ + strcpy(File + nFileLen, STR_INI_EXTENSION); + nFileLen += strlen(STR_INI_EXTENSION); + + rtl_uString_release( strProgName ); + } + + if (File[0] == 0) + return sal_False; + + /* build directory path */ + if (strPath && strPath->length) + { + sal_Unicode *pPath = rtl_uString_getStr(strPath); + sal_Int32 nLen = rtl_uString_getLength(strPath); + + if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METAHOME) , STR_INI_METAHOME) == 0) && + ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)] == '/'))) + { + rtl_uString * strHome = NULL; + oslSecurity security = osl_getCurrentSecurity(); + + bFailed = ! osl_getHomeDir(security, &strHome); + osl_freeSecurityHandle(security); + + if (bFailed) return (sal_False); + + if (strHome->length >= _MAX_PATH) + return sal_False; + + strcpy( Path, strHome->buffer); + nPathLen = strHome->length; + + if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)) + { + pPath += RTL_CONSTASCII_LENGTH(STR_INI_METAHOME); + nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METAHOME); + + if (nLen + nPathLen >= _MAX_PATH) + return sal_False; + + strcpy(Path + nPathLen, pPath); + nPathLen += nLen; + } + + rtl_uString_release(strHome); + } + + else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METACFG), STR_INI_METACFG) == 0) && + ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METACFG)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METACFG)] == '/'))) + { + rtl_uString * strConfig = NULL; + oslSecurity security = osl_getCurrentSecurity(); + + bFailed = ! osl_getConfigDir(security, &strConfig); + osl_freeSecurityHandle(security); + + if (bFailed) return (sal_False); + + if (strConfig->length >= _MAX_PATH) + return sal_False; + + strcpy( Path, strConfig->buffer); + nPathLen = strConfig->length; + + if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METACFG)) + { + pPath += RTL_CONSTASCII_LENGTH(STR_INI_METACFG); + nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METACFG); + + if (nLen + nPathLen >= _MAX_PATH) + return sal_False; + + strcpy(Path + nPathLen, pPath); + nPathLen += nLen; + } + + rtl_uString_release(strConfig); + } + + else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METASYS), STR_INI_METASYS) == 0) && + ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METASYS)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METASYS)] == '/'))) + { + if (((nPathLen = GetWindowsDirectoryW(Path, _MAX_PATH)) == 0) || (nPathLen >= _MAX_PATH)) + return (sal_False); + + if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METASYS)) + { + pPath += RTL_CONSTASCII_LENGTH(STR_INI_METASYS); + nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METASYS); + + if (nLen + nPathLen >= MAX_PATH) + return sal_False; + + strcpy(Path + nPathLen, pPath); + nPathLen += nLen; + } + } + + else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METAINS), STR_INI_METAINS) == 0) && + ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METAINS)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAINS)] == '/') || + (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAINS)] == '"') ) ) + { + if (! lookupProfile(pPath + RTL_CONSTASCII_LENGTH(STR_INI_METAINS), File, Path)) + return (sal_False); + + nPathLen = strlen(Path); + } + + else if(nLen < MAX_PATH) + { + strcpy(Path, pPath); + nPathLen = strlen(Path); + } + else + return sal_False; + } + else + { + rtl_uString * strConfigDir = NULL; + oslSecurity security = osl_getCurrentSecurity(); + + bFailed = ! osl_getConfigDir(security, &strConfigDir); + osl_freeSecurityHandle(security); + + if (bFailed) return (sal_False); + if (strConfigDir->length >= MAX_PATH) + return sal_False; + + strcpy(Path, strConfigDir->buffer); + nPathLen = strConfigDir->length; + } + + if (nPathLen && (Path[nPathLen - 1] != L'/') && (Path[nPathLen - 1] != L'\\')) + { + Path[nPathLen++] = L'\\'; + Path[nPathLen] = 0; + } + + if (nPathLen + nFileLen >= MAX_PATH) + return sal_False; + + /* append file name */ + strcpy(Path + nPathLen, File); + nPathLen += nFileLen; + + /* copy filename */ + rtl_uString_newFromStr_WithLength(&strTmp, Path, nPathLen); + nError = osl_getFileURLFromSystemPath(strTmp, strProfileName); + rtl_uString_release(strTmp); + + return nError == osl_File_E_None; +} +#endif // 0 // YD + + +/*****************************************************************************/ +/* Static Module Functions */ +/*****************************************************************************/ + +static osl_TStamp getFileStamp(osl_TFile* pFile) +{ + osl_TStamp FileTime; + FILESTATUS3 FileStatus; + sal_uInt32 Bytes; + + Bytes = sizeof( FILESTATUS3 ); + if ( (!pFile->m_Handle) || + DosQueryFileInfo(pFile->m_Handle, FIL_STANDARD, &FileStatus, Bytes)) + memset(&FileTime, 0, sizeof(FileTime)); + else + { + FileTime.m_Date = FileStatus.fdateLastWrite; + FileTime.m_Time = FileStatus.ftimeLastWrite; + } + + return (FileTime); +} + +static sal_Bool lockFile(const osl_TFile* pFile, osl_TLockMode eMode) +{ + sal_uInt32 status = 1; + FILELOCK Lock; + + if (!pFile->m_Handle) + return (sal_False); + + Lock.lOffset = 0; + Lock.lRange = 0xFFFFFFFF; + + switch (eMode) + { + case un_lock: + status = DosSetFileLocks(pFile->m_Handle, &Lock, NULL, 1000, 0); + break; + + case read_lock: + status = DosSetFileLocks(pFile->m_Handle, NULL, &Lock, 1000, 1); + break; + + case write_lock: + status = DosSetFileLocks(pFile->m_Handle, NULL, &Lock, 1000, 0); + break; + } + + return (status == 0); +} + +//static osl_TFile* openFile(rtl_uString* pszFilename, sal_Bool bWriteable) +static osl_TFile* openFileImpl(rtl_uString *ustrFileName, oslProfileOption ProfileFlags ) +{ + sal_uInt32 action; + APIRET rc; + osl_TFile* pFile = (osl_TFile*)calloc(1, sizeof(osl_TFile)); + + ULONG attributes; + ULONG flags; + ULONG mode; + sal_Bool bWriteable = sal_False; + rtl_String* strFileName=0; + sal_Char* pszFileName=0; + + /* check parameters */ + OSL_ASSERT( ustrFileName ); + + rtl_uString2String( &strFileName, + rtl_uString_getStr(ustrFileName), + rtl_uString_getLength(ustrFileName), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszFileName = rtl_string_getStr(strFileName); + +/* if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE | osl_Profile_READWRITE ) )*/ + if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("setting bWriteable to TRUE\n"); +#endif + bWriteable=sal_True; + } + + if (bWriteable) + { + flags = FILE_NORMAL | FILE_ARCHIVED; + attributes = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + mode = OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE; + } + else + { + flags = FILE_NORMAL; + attributes = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + mode = OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY; + } + + if (rc = DosOpen((PCSZ)pszFileName, &pFile->m_Handle, &action, 0, flags, attributes, mode, NULL)) + { + if (rc == ERROR_TOO_MANY_OPEN_FILES) + { + LONG fhToAdd = 10; + ULONG fhOld = 0; + rc = DosSetRelMaxFH(&fhToAdd, &fhOld); + rc = DosOpen((PCSZ)pszFileName, &pFile->m_Handle, &action, 0, flags, attributes, mode, NULL); + } + } + + if ( (rc != NO_ERROR) && bWriteable) + { + free(pFile); + rtl_string_release(strFileName); + return (NULL); + } + + rtl_string_release(strFileName); + + pFile->m_pWriteBuf=0; + pFile->m_nWriteBufFree=0; + pFile->m_nWriteBufLen=0; + + if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("locking '%s' file\n",pszFilename); +#endif + + lockFile(pFile, bWriteable ? write_lock : read_lock); + } + + /* mfe: new WriteBuf obsolete */ +/* pFile->m_pWritePtr = pFile->m_Buf;*/ +/* pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);*/ + + return (pFile); +} + +//static osl_TStamp closeFile(osl_TFile* pFile) +static osl_TStamp closeFileImpl(osl_TFile* pFile) +{ + osl_TStamp stamp = {0, 0}; + + if ( pFile == 0 ) + { + return stamp; + } + + if (pFile->m_Handle) + { + /* mfe: new WriteBuf obsolete */ + /* we just closing the file here, DO NOT write, it has to be handled in higher levels */ + //if (pFile->m_pWritePtr > pFile->m_WriteBuf) + //{ + // sal_uInt32 Bytes; + + // DosWrite(pFile->m_Handle, pFile->m_WriteBuf, + // pFile->m_pWritePtr - pFile->m_WriteBuf, + // &Bytes); + //} + + stamp = getFileStamp(pFile); + + lockFile(pFile, un_lock); + + DosClose(pFile->m_Handle); + } + + if ( pFile->m_pWriteBuf != 0 ) + { + free(pFile->m_pWriteBuf); + } + + free(pFile); + + return(stamp); +} + +static sal_Bool rewindFile(osl_TFile* pFile, sal_Bool bTruncate) +{ + if (pFile->m_Handle) + { + sal_uInt32 Position; + + /* mfe: new WriteBuf obsolete */ + /* we just closing the file here, DO NOT write, it has to be handled in higher levels */ + /* if (pFile->m_pWritePtr > pFile->m_WriteBuf) + { + sal_uInt32 Bytes; + + DosWrite(pFile->m_Handle, pFile->m_WriteBuf, + pFile->m_pWritePtr - pFile->m_WriteBuf, + &Bytes); + + pFile->m_pWritePtr = pFile->m_WriteBuf; + } */ + + pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + + DosSetFilePtr(pFile->m_Handle, 0, FILE_BEGIN, &Position); + + if (bTruncate) + DosSetFileSize(pFile->m_Handle, 0); + } + + return (sal_True); +} + +static sal_Bool getLine(osl_TFile* pFile, const sal_Char *pszLine, int MaxLen) +{ + int Free, Bytes; + sal_Char* pChr; + sal_Char* pLine = (sal_Char *)pszLine; + sal_uInt32 Max; + + if (pFile->m_Handle == 0) + return (sal_False); + + MaxLen -= 1; + + do + { + Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf); + + if (Bytes <= 1) + { + /* refill buffer */ + memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes); + pFile->m_pReadPtr = pFile->m_ReadBuf; + + Free = sizeof(pFile->m_ReadBuf) - Bytes; + + if (DosRead(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free, &Max)) + { + *pLine = '\0'; + return (sal_False); + } + + if (Max < Free) + { + if ((Max == 0) && (pLine == pszLine)) + { + *pLine = '\0'; + return (sal_False); + } + + pFile->m_ReadBuf[Bytes + Max] = '\0'; + } + } + + for (pChr = pFile->m_pReadPtr; + (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') && + (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)); + pChr++); + + Max = min(pChr - pFile->m_pReadPtr, MaxLen); + memcpy(pLine, pFile->m_pReadPtr, Max); + MaxLen -= Max; + pLine += Max; + + if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)) + { + if (*pChr != '\0') + { + if ((pChr[0] == '\r') && (pChr[1] == '\n')) + pChr += 2; + else + pChr += 1; + } + + if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) && + (*pChr == '\0')) + pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + + *pLine = '\0'; + + /* setting MaxLen to -1 indicates terminating read loop */ + MaxLen = -1; + } + + pFile->m_pReadPtr = pChr; + } + while (MaxLen > 0); + + return (sal_True); +} + +static sal_Bool putLine(osl_TFile* pFile, const sal_Char *pszLine) +{ + unsigned int Len = strlen(pszLine); + +#ifdef DEBUG_OSL_PROFILE + int strLen=0; +#endif + + if ( pFile == 0 || pFile->m_Handle < 0 ) + { + return (sal_False); + } + + if ( pFile->m_pWriteBuf == 0 ) + { + pFile->m_pWriteBuf = (sal_Char*) malloc(Len+3); + pFile->m_nWriteBufLen = Len+3; + pFile->m_nWriteBufFree = Len+3; + } + else + { + if ( pFile->m_nWriteBufFree <= Len + 3 ) + { + sal_Char* pTmp; + + pTmp=(sal_Char*) realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) ); + if ( pTmp == 0 ) + { + return sal_False; + } + pFile->m_pWriteBuf = pTmp; + pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len ); + pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2; + memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree); + } + } + + + + memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1); +#ifdef DEBUG_OSL_PROFILE + strLen = strlen(pFile->m_pWriteBuf); +#endif + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\r'; + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\n'; + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 2]='\0'; + + pFile->m_nWriteBufFree-=Len+2; + +#ifdef DEBUG_OSL_PROFILE +/* OSL_TRACE("File Buffer in _putLine '%s' '%i'(%i)\n",pFile->m_pWriteBuf,strlen(pFile->m_pWriteBuf),pFile->m_nWriteBufLen - pFile->m_nWriteBufFree);*/ +#endif + + return (sal_True); +} + +/* platform specific end */ + +static const sal_Char* stripBlanks(const sal_Char* String, sal_uInt32* pLen) +{ + if ( (pLen != NULL) && ( *pLen != 0 ) ) + { + while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t')) + (*pLen)--; + + while ((*String == ' ') || (*String == '\t')) + { + String++; + (*pLen)--; + } + } + else + while ((*String == ' ') || (*String == '\t')) + String++; + + return (String); +} + +static const sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == NULL) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *)); + } + else + { + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(sal_Char *)); + } + + if (pProfile->m_Lines == NULL) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return (NULL); + } + + } + + pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line); + + return (pProfile->m_Lines[pProfile->m_NoLines - 1]); +} + +static const sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == NULL) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *)); + } + else + { + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(sal_Char *)); + } + + if (pProfile->m_Lines == NULL) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return (NULL); + } + + } + + LineNo = LineNo > pProfile->m_NoLines ? pProfile->m_NoLines : LineNo; + + if (LineNo < pProfile->m_NoLines) + { + sal_uInt32 i, n; + osl_TProfileSection* pSec; + + memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo], + (pProfile->m_NoLines - LineNo) * sizeof(sal_Char *)); + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line >= LineNo) + pSec->m_Line++; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line >= LineNo) + pSec->m_Entries[n].m_Line++; + } + } + + pProfile->m_NoLines++; + + pProfile->m_Lines[LineNo] = strdup(Line); + + return (pProfile->m_Lines[LineNo]); +} + +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo) +{ + if (LineNo < pProfile->m_NoLines) + { + free(pProfile->m_Lines[LineNo]); + if (pProfile->m_NoLines - LineNo > 1) + { + sal_uInt32 i, n; + osl_TProfileSection* pSec; + + memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1], + (pProfile->m_NoLines - LineNo - 1) * sizeof(sal_Char *)); + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line > LineNo) + pSec->m_Line--; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line > LineNo) + pSec->m_Entries[n].m_Line--; + } + } + else + { + pProfile->m_Lines[LineNo] = 0; + } + + pProfile->m_NoLines--; + } + + return; +} + +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + const sal_Char* Entry, sal_uInt32 Len) +{ + Entry = stripBlanks(Entry, &Len); + pSection->m_Entries[NoEntry].m_Line = Line; + pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line]; + pSection->m_Entries[NoEntry].m_Len = Len; + + return; +} + +static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, const sal_Char* Entry, sal_uInt32 Len) +{ + if (pSection != NULL) + { + if (pSection->m_NoEntries >= pSection->m_MaxEntries) + { + if (pSection->m_Entries == NULL) + { + pSection->m_MaxEntries = ENTRIES_INI; + pSection->m_Entries = (osl_TProfileEntry *)malloc( + pSection->m_MaxEntries * sizeof(osl_TProfileEntry)); + } + else + { + pSection->m_MaxEntries += ENTRIES_ADD; + pSection->m_Entries = (osl_TProfileEntry *)realloc(pSection->m_Entries, + pSection->m_MaxEntries * sizeof(osl_TProfileEntry)); + } + + if (pSection->m_Entries == NULL) + { + pSection->m_NoEntries = 0; + pSection->m_MaxEntries = 0; + return (sal_False); + } + } + + pSection->m_NoEntries++; + + Entry = stripBlanks(Entry, &Len); + setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line, + Entry, Len); + + return (sal_True); + } + + return (sal_False); +} + +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry) +{ + if (NoEntry < pSection->m_NoEntries) + { + if (pSection->m_NoEntries - NoEntry > 1) + memmove(&pSection->m_Entries[NoEntry], + &pSection->m_Entries[NoEntry + 1], + (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry)); + pSection->m_NoEntries--; + } + + return; +} + +static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len) +{ + if (pProfile->m_NoSections >= pProfile->m_MaxSections) + { + if (pProfile->m_Sections == NULL) + { + pProfile->m_MaxSections = SECTIONS_INI; + pProfile->m_Sections = (osl_TProfileSection *)malloc(pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + } + else + { + pProfile->m_MaxSections += SECTIONS_ADD; + pProfile->m_Sections = (osl_TProfileSection *)realloc(pProfile->m_Sections, + pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + } + + if (pProfile->m_Sections == NULL) + { + pProfile->m_NoSections = 0; + pProfile->m_MaxSections = 0; + return (sal_False); + } + } + + pProfile->m_NoSections++; + + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = NULL; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries = 0; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0; + + Section = (sal_Char *)stripBlanks(Section, &Len); + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line]; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len; + + return (sal_True); +} + +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection) +{ + sal_uInt32 Section; + + if ((Section = pSection - pProfile->m_Sections) < pProfile->m_NoSections) + { + free (pSection->m_Entries); + if (pProfile->m_NoSections - Section > 1) + { + memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1], + (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection)); + } + else + { + pSection->m_Entries = 0; + } + + pProfile->m_NoSections--; + } + + return; +} + +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section, + const sal_Char* Entry, sal_uInt32 *pNoEntry) +{ +static sal_uInt32 Sect = 0; + sal_uInt32 i, n; + sal_uInt32 Len; + const sal_Char* pStr; + osl_TProfileSection* pSec; + + Len = strlen(Section); + Section = (sal_Char *)stripBlanks(Section, &Len); + + n = Sect; + + for (i = 0; i < pProfile->m_NoSections; i++) + { + n %= pProfile->m_NoSections; + pSec = &pProfile->m_Sections[n]; + if ((Len == pSec->m_Len) && + (strnicmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len) + == 0)) + break; + n++; + } + + Sect = n; + + if (i < pProfile->m_NoSections) + { + Len = strlen(Entry); + Entry = stripBlanks(Entry, &Len); + + *pNoEntry = pSec->m_NoEntries; + + for (i = 0; i < pSec->m_NoEntries; i++) + { + pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset]; + if ((Len == pSec->m_Entries[i].m_Len) && + (strnicmp(Entry, pStr, pSec->m_Entries[i].m_Len) + == 0)) + { + *pNoEntry = i; + break; + } + } + } + else + pSec = NULL; + + return (pSec); +} + +static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile) +{ + sal_uInt32 i; + sal_Char* pStr; + sal_Char* pChar; + sal_Char Line[1024]; + + pProfile->m_NoLines = 0; + pProfile->m_NoSections = 0; + + OSL_VERIFY(rewindFile(pFile, sal_False)); + + while (getLine(pFile, Line, sizeof(Line))) + { + if (! addLine(pProfile, Line)) + return (sal_False); + } + + for (i = 0; i < pProfile->m_NoLines; i++) + { + pStr = (sal_Char *)stripBlanks(pProfile->m_Lines[i], NULL); + + if ((*pStr == '\0') || (*pStr == ';')) + continue; + + if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == NULL) || + ((pChar - pStr) <= 2)) + { + /* insert entry */ + + if (pProfile->m_NoSections < 1) + continue; + + if ((pChar = strchr(pStr, '=')) == NULL) + pChar = pStr + strlen(pStr); + + if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1], + i, pStr, pChar - pStr)) + return (sal_False); + } + else + { + /* new section */ + + if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1)) + return (sal_False); + } + } + + return (sal_True); +} + +static sal_Bool storeProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile, sal_Bool bCleanup) +{ + if (pProfile->m_Lines != NULL) + { + if (pProfile->m_Flags & FLG_MODIFIED) + { + sal_uInt32 i; + + OSL_VERIFY(rewindFile(pFile, sal_True)); + + for (i = 0; i < pProfile->m_NoLines; i++) + OSL_VERIFY(putLine(pFile, pProfile->m_Lines[i])); + + pProfile->m_Flags &= ~FLG_MODIFIED; + } + + if (bCleanup) + { + while (pProfile->m_NoLines > 0) + removeLine(pProfile, pProfile->m_NoLines - 1); + + free(pProfile->m_Lines); + pProfile->m_Lines = NULL; + pProfile->m_MaxLines = 0; + + while (pProfile->m_NoSections > 0) + removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]); + + free(pProfile->m_Sections); + pProfile->m_Sections = NULL; + pProfile->m_MaxSections = 0; + } + } + + return (sal_True); +} + +static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile; + oslProfileOption PFlags=0; + + + if ( bWriteable ) + { +/* PFlags = osl_Profile_DEFAULT | osl_Profile_READWRITE; */ + PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK; + } + else + { + PFlags = osl_Profile_DEFAULT; + } + + + if (pProfile == NULL) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("AUTOOPEN MODE\n"); +#endif + + if ((pProfile = (osl_TProfileImpl*)osl_openProfile(NULL, PFlags)) != NULL ) + { + pProfile->m_Flags |= FLG_AUTOOPEN; + } + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("try to acquire\n"); +#endif + + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | + osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE))) + { + osl_TStamp Stamp; +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("DEFAULT MODE\n"); +#endif + if (! (pProfile->m_pFile = openFileImpl(pProfile->m_strFileName, pProfile->m_Flags | PFlags))) + return NULL; + + Stamp = getFileStamp(pProfile->m_pFile); + + if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp))) + { + pProfile->m_Stamp = Stamp; + + loadProfile(pProfile->m_pFile, pProfile); + } + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("READ/WRITELOCK MODE\n"); +#endif + + + /* A readlock file could not be written */ + if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable) + { + return (NULL); + } + } + } + else + { + sal_Bool bWriteable = sal_False; + char pszFilename[PATH_MAX] = ""; + + if ( pProfile->m_strFileName != 0 && pProfile->m_strFileName->buffer[0] != 0 ) + FileURLToPath( pszFilename, PATH_MAX, pProfile->m_strFileName ); + /* hack: usualy you have a specific HAB, but NULL works here... */ + pProfile->m_hIni = PrfOpenProfile(NULL, (PCSZ)pszFilename); + if (! pProfile->m_hIni) + return (NULL); + } + } + + return (pProfile); +} + +static sal_Bool releaseProfile(osl_TProfileImpl* pProfile) +{ +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In releaseProfile\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [profile==0]\n"); +#endif + return sal_False; + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (pProfile->m_Flags & FLG_AUTOOPEN) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [AUTOOPEN]\n"); +#endif + return (osl_closeProfile((oslProfile)pProfile)); + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("DEFAULT MODE\n"); +#endif + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | + osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE))) + { + if (pProfile->m_Flags & FLG_MODIFIED) + storeProfile(pProfile->m_pFile, pProfile, sal_False); + + closeFileImpl(pProfile->m_pFile); + pProfile->m_pFile = NULL; + } + } + } + else + PrfCloseProfile(pProfile->m_hIni); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [ok]\n"); +#endif + return (sal_True); +} + +#if 0 // YD + +static sal_Bool lookupProfile(const sal_Char *pszPath, const sal_Char *pszFile, sal_Char *pPath) +{ + sal_Char *pChr, *pStr; + sal_Char Path[_MAX_PATH] = ""; + sal_Char Product[132] = ""; + sal_Char Buffer[1024]; + + if (*pszPath == '"') + { + int i = 0; + + pszPath++; + + while ((*pszPath != '"') && (*pszPath != '\0')) + Product[i++] = *pszPath++; + + Product[i] = '\0'; + + if (*pszPath == '"') + pszPath++; + + if ( (*pszPath == '/') || (*pszPath == '\\') ) + { + pszPath++; + } + } + else + { + /* if we have not product identfication, do a special handling for soffice.ini */ + if (stricmp(SVERSION_PROFILE, pszFile) == 0) + { + sal_Char Profile[_MAX_PATH]; + sal_Char Dir[_MAX_PATH]; + oslProfile hProfile; + + /* open sversion.ini in the system directory, and try to locate the entry + with the highest version for StarOffice */ + if ((osl_getProfileName(SVERSION_FALLBACK, SVERSION_NAME, Profile, sizeof(Profile))) && + (hProfile = osl_openProfile(Profile, osl_Profile_READLOCK))) + { + osl_getProfileSectionEntries(hProfile, SVERSION_SECTION, + Buffer, sizeof(Buffer)); + + for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1) + { + if ((strnicmp(pChr, SVERSION_SOFFICE, sizeof(SVERSION_SOFFICE) - 1) == 0) && + (stricmp(Product, pChr) < 0)) + { + osl_readProfileString(hProfile, SVERSION_SECTION, pChr, + Dir, sizeof(Dir), ""); + + /* check for existence of path */ + if (access(Dir, 0) >= 0) + strcpy(Product, pChr); + } + } + + osl_closeProfile(hProfile); + } + + /* open sversion.ini in the users directory, and try to locate the entry + with the highest version for StarOffice */ + if ((strcmp(SVERSION_LOCATION, SVERSION_FALLBACK) != 0) && + (osl_getProfileName(SVERSION_LOCATION, SVERSION_NAME, Profile, sizeof(Profile))) && + (hProfile = osl_openProfile(Profile, osl_Profile_READLOCK))) + { + osl_getProfileSectionEntries(hProfile, SVERSION_SECTION, + Buffer, sizeof(Buffer)); + + for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1) + { + if ((strnicmp(pChr, SVERSION_SOFFICE, sizeof(SVERSION_SOFFICE) - 1) == 0) && + (stricmp(Product, pChr) < 0)) + { + osl_readProfileString(hProfile, SVERSION_SECTION, pChr, + Dir, sizeof(Dir), ""); + + /* check for existence of path */ + if (access(Dir, 0) >= 0) + strcpy(Product, pChr); + } + } + + osl_closeProfile(hProfile); + } + + /* remove any trailing build number */ + if ((pChr = strrchr(Product, '/')) != NULL) + *pChr = '\0'; + } + } + + + /* if we have an userid option eg. "-userid:rh[/usr/home/rh/staroffice]", + this will supercede all other locations */ + if (osl_getCommandArgs(Buffer, sizeof(Buffer)) == osl_Process_E_None) + { + sal_Char *pStart, *pEnd; + + for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1) + if (((*pChr == '-') || (*pChr == '+')) && + (strnicmp(pChr + 1, SVERSION_OPTION, sizeof(SVERSION_OPTION) - 1) == 0)) + { + if (((pStart = strchr(pChr + sizeof(SVERSION_OPTION), '[')) != NULL) && + ((pEnd = strchr(pStart + 1, ']')) != NULL)) + { + strncpy(Path, pStart + 1, pEnd - (pStart + 1)); + Path[pEnd - (pStart + 1)] = '\0'; + + /* build full path */ + if ((Path[strlen(Path) - 1] != '/') && (Path[strlen(Path) - 1] != '\\')) + { + strcat(Path, "\\"); + } + + pChr =&Path[strlen(Path)]; + if ( strlen(pszPath) <= 0 ) + { + strcat(Path,SVERSION_USER); + + if ( access(Path, 0) < 0 ) + { + *pChr='\0'; + } + } + else + { + strcat(Path, pszPath); + } + + break; + } + } + } + + if (strlen(Path) <= 0) + { + /* try to find the file in the directory of the executbale */ + if (osl_getExecutableFile(Path, sizeof(Path)) != osl_Process_E_None) + return (sal_False); + + /* seperate path from filename */ + if ((pChr = strrchr(Path, '\\')) == NULL) + if ((pChr = strrchr(Path, ':')) == NULL) + return (sal_False); + else + *pChr = '\0'; + else + *pChr = '\0'; + + /* if we have no product identification use the executable file name */ + if (strlen(Product) <= 0) + { + strcpy(Product, pChr + 1); + + /* remove extension */ + if ((pChr = strrchr(Product, '.')) != NULL) + *pChr = '\0'; + } + + /* remember last subdir */ + pStr = strrchr(Path, '\\'); + + strcat(Path, "\\"); + + if ( strlen(pszPath) <= 0 ) + { + strcat(Path, pszPath); + } + else + { + strcat(Path,pszPath); + } + + /* if file not exists, remove any specified subdirectories + like "bin" or "program" */ + if (((access(Path, 0) < 0) && (pStr != NULL)) || (strlen(pszPath) <= 0)) + { + static sal_Char *SubDirs[] = SVERSION_DIRS; + + int i = 0; + + for (i = 0; i < (sizeof(SubDirs) / sizeof(SubDirs[0])); i++) + if (strnicmp(pStr + 1, SubDirs[i], strlen(SubDirs[i])) == 0) + { + if ( strlen(pszPath) <= 0) + { + strcpy(pStr + 1,SVERSION_USER); + if ( access(Path, 0) < 0 ) + { + *(pStr+1)='\0'; + } + } + else + { + strcpy(pStr + 1, pszPath); + } + + break; + } + } + + pChr = &Path[strlen(Path)]; + if ((Path[strlen(Path) - 1] != '/') && (Path[strlen(Path) - 1] != '\\')) + strcat(Path, "\\"); + strcat(Path, pszFile); + + if ((access(Path, 0) < 0) && (strlen(Product) > 0)) + { + sal_Char Profile[_MAX_PATH]; + oslProfile hProfile; + + /* remove appended filename */ + *pChr = '\0'; + + /* open sversion.ini in the system directory, and try to locate the entry + with the highest version for StarOffice */ + if ((osl_getProfileName(SVERSION_LOCATION, SVERSION_NAME, Profile, sizeof(Profile))) && + (hProfile = osl_openProfile(Profile, osl_Profile_READLOCK))) + { + pChr = &Product[strlen(Product)]; + + /* append build number */ + strcat(Product, "/"); + strcat(Product, BUILD_STR(SUPD)); + + osl_readProfileString(hProfile, SVERSION_SECTION, Product, + Buffer, sizeof(Buffer), ""); + + /* if not found, try it without build number */ + if (strlen(Buffer) <= 0) + { + *pChr = '\0'; + + osl_readProfileString(hProfile, SVERSION_SECTION, Product, + Buffer, sizeof(Buffer), ""); + + osl_closeProfile(hProfile); + + /* if not found, try the fallback */ + if ((strlen(Buffer) <= 0) && (strcmp(SVERSION_LOCATION, SVERSION_FALLBACK) != 0)) + { + if ((osl_getProfileName(SVERSION_FALLBACK, SVERSION_NAME, Profile, sizeof(Profile))) && + (hProfile = osl_openProfile(Profile, osl_Profile_READLOCK))) + { + /* prepare build number */ + *pChr = '/'; + + osl_readProfileString(hProfile, SVERSION_SECTION, Product, + Buffer, sizeof(Buffer), ""); + + /* if not found, try it without build number */ + if (strlen(Buffer) <= 0) + { + *pChr = '\0'; + + osl_readProfileString(hProfile, SVERSION_SECTION, Product, + Buffer, sizeof(Buffer), ""); + } + + osl_closeProfile(hProfile); + } + } + } + else + osl_closeProfile(hProfile); + + if (strlen(Buffer) > 0) + { + strcpy(Path, Buffer); + + /* build full path */ + if ((Path[strlen(Path) - 1] != '/') && (Path[strlen(Path) - 1] != '\\')) + { + if ((*pszPath != '/') && (*pszPath != '\\')) + strcat(Path, "\\"); + } + + pChr=&Path[strlen(pszPath)]; + if ( strlen(pszPath) > 0 ) + { + strcat(Path, pszPath); + } + else + { + strcat(Path,SVERSION_USER); + if ( access(Path, 0) < 0 ) + { + *pChr='\0'; + } + } + } + } + } + else + /* remove appended filename */ + *pChr = '\0'; + } + + strcpy(pPath, Path); + + return (sal_True); +} + +#endif // 0 // YD + diff --git a/sal/osl/os2/salinit.cxx b/sal/osl/os2/salinit.cxx new file mode 100644 index 000000000000..f932f2ea1b50 --- /dev/null +++ b/sal/osl/os2/salinit.cxx @@ -0,0 +1,120 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define INCL_DOS +#include <os2.h> + +#include "precompiled_sal.hxx" +#include "sal/config.h" + +#include "osl/process.h" +#include "sal/main.h" +#include "sal/types.h" + +// for exception logging +#include <stdio.h> +#include <string.h> +#include <setjmp.h> +#include "helpers/except.h" + +extern "C" { + +/*----------------------------------------------------------------------------*/ + +static CHAR szOOoExe[CCHMAXPATH]; + +static FILE* APIENTRY _oslExceptOpenLogFile(VOID) +{ + FILE *file; + DATETIME DT; + PPIB pib; + PSZ slash; + + // get executable fullpath + DosGetInfoBlocks(NULL, &pib); + DosQueryModuleName(pib->pib_hmte, sizeof(szOOoExe), szOOoExe); + // truncate to exe name + slash = (PSZ)strrchr( szOOoExe, '.'); + *slash = '\0'; + // make log path + strcat( szOOoExe, ".log"); + + file = fopen( szOOoExe, "a"); + if (!file) { // e.g. readonly drive + // try again, usually C exist and is writable + file = fopen( "c:\\OOo.log", "a"); + } + if (file) { + DosGetDateTime(&DT); + fprintf(file, "\nTrap message -- Date: %04d-%02d-%02d, Time: %02d:%02d:%02d\n", + DT.year, DT.month, DT.day, + DT.hours, DT.minutes, DT.seconds); + fprintf(file, "-------------------------------------------------------\n" + "\nAn internal error occurred (Built " __DATE__ "-" __TIME__ ").\n"); + + } + + // ok, return handle + return (file); +} + +/*----------------------------------------------------------------------------*/ + +static EXCEPTSTRUCT g_excptstruct = {0}; + +void SAL_CALL sal_detail_initialize(int argc, char ** argv) +{ + APIRET rc = -1; + +#if OSL_DEBUG_LEVEL == 0 + excRegisterHooks(_oslExceptOpenLogFile, NULL, NULL, FALSE); + + g_excptstruct.RegRec2.pfnHandler = (PFN)excHandlerLoud; + g_excptstruct.arc = DosSetExceptionHandler( + (PEXCEPTIONREGISTRATIONRECORD)&(g_excptstruct.RegRec2)); + + if (g_excptstruct.arc) + if (G_pfnExcHookError) + G_pfnExcHookError(__FILE__, __LINE__, __FUNCTION__, g_excptstruct.arc); + else + DosBeep(1000, 1000); + g_excptstruct.ulExcpt = setjmp(g_excptstruct.RegRec2.jmpThread); +#endif + + osl_setCommandArgs(argc, argv); +} + +void SAL_CALL sal_detail_deinitialize() +{ + APIRET rc = -1; + +#if OSL_DEBUG_LEVEL == 0 + rc = DosUnsetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&(g_excptstruct.RegRec2)); +#endif +} + +} diff --git a/sal/osl/os2/secimpl.h b/sal/osl/os2/secimpl.h new file mode 100644 index 000000000000..6922a6d3c0ce --- /dev/null +++ b/sal/osl/os2/secimpl.h @@ -0,0 +1,50 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_SECURITYIMPL_H_ +#define _OSL_SECURITYIMPL_H_ + +#include <osl/security.h> + +#define PASSWD_BUFFER_SIZE 1024 /* recommended, see 'man getpwnam_r' */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _oslSecurityImpl { + int m_isValid; + struct passwd m_pPasswd; + sal_Char m_buffer[PASSWD_BUFFER_SIZE]; +} oslSecurityImpl; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/os2/security.c b/sal/osl/os2/security.c new file mode 100644 index 000000000000..f03be57acc85 --- /dev/null +++ b/sal/osl/os2/security.c @@ -0,0 +1,317 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/security.h> +#include <osl/diagnose.h> +#include <osl/module.h> + +#include "osl/thread.h" +#include "osl/file.h" + +#ifdef SOLARIS +#include <crypt.h> +#endif + +#include "secimpl.h" + +#ifndef PAM_BINARY_MSG +#define PAM_BINARY_MSG 6 +#endif + +extern oslModule SAL_CALL osl_psz_loadModule(const sal_Char *pszModuleName, sal_Int32 nRtldMode); +extern void* SAL_CALL osl_psz_getSymbol(oslModule hModule, const sal_Char* pszSymbolName); +extern oslSecurityError SAL_CALL +osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd, + oslSecurity* pSecurity); +sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax); +sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax); +sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax); +sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax); + + + +oslSecurity SAL_CALL osl_getCurrentSecurity() +{ + + oslSecurityImpl *pSecImpl = (oslSecurityImpl*) malloc(sizeof(oslSecurityImpl)); + struct passwd *pPasswd = getpwuid(getuid()); + + if (pPasswd) + { + memcpy(&pSecImpl->m_pPasswd, pPasswd, sizeof(pSecImpl->m_pPasswd)); + pSecImpl->m_isValid = sal_True; + } + else + { + /* Some UNIX-OS don't implement getpwuid, e.g. NC OS (special NetBSD) 1.2.1 */ + /* so we have to catch this in this else branch */ + pSecImpl->m_pPasswd.pw_name = getenv("USER"); + pSecImpl->m_pPasswd.pw_dir = getenv("HOME"); + if (pSecImpl->m_pPasswd.pw_name && pSecImpl->m_pPasswd.pw_dir) + pSecImpl->m_isValid = sal_True; + else + { + pSecImpl->m_pPasswd.pw_name = "unknown"; + pSecImpl->m_pPasswd.pw_dir = "/tmp"; + pSecImpl->m_isValid = sal_False; + } + pSecImpl->m_pPasswd.pw_passwd = NULL; + pSecImpl->m_pPasswd.pw_uid = getuid(); + pSecImpl->m_pPasswd.pw_gid = getgid(); + pSecImpl->m_pPasswd.pw_gecos = "unknown"; + pSecImpl->m_pPasswd.pw_shell = "unknown"; + } + + + return ((oslSecurity)pSecImpl); +} + + +oslSecurityError SAL_CALL osl_loginUser( + rtl_uString *ustrUserName, + rtl_uString *ustrPassword, + oslSecurity *pSecurity + ) +{ + oslSecurityError ret; + + *pSecurity = osl_getCurrentSecurity(); + ret = osl_Security_E_None; + + return ret; +} + + + +oslSecurityError SAL_CALL osl_loginUserOnFileServer( + rtl_uString *strUserName, + rtl_uString *strPasswd, + rtl_uString *strFileServer, + oslSecurity *pSecurity + ) +{ + oslSecurityError erg; + return erg = osl_Security_E_UserUnknown; +} + + +oslSecurityError SAL_CALL osl_psz_loginUserOnFileServer( const sal_Char* pszUserName, + const sal_Char* pszPasswd, + const sal_Char* pszFileServer, + oslSecurity* pSecurity ) +{ + oslSecurityError erg; + return erg = osl_Security_E_UserUnknown; +} + +sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent) +{ + sal_Bool bRet=sal_False; + sal_Char pszIdent[1024]; + + pszIdent[0] = '\0'; + + bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent)); + + rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*ustrIdent != NULL); + + return bRet; +} + + +sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax) +{ + sal_Char buffer[32]; + sal_Int32 nChr; + + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid); + if ( nChr < 0 || nChr >= sizeof(buffer) || nChr >= nMax ) + return sal_False; /* leave *pszIdent unmodified in case of failure */ + + memcpy(pszIdent, buffer, nChr+1); + return sal_True; +} + +sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName) +{ + sal_Bool bRet=sal_False; + sal_Char pszName[1024]; + + pszName[0] = '\0'; + + bRet = osl_psz_getUserName(Security,pszName,sizeof(pszName)); + + rtl_string2UString( ustrName, pszName, rtl_str_getLength( pszName ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*ustrName != NULL); + + return bRet; +} + + + +sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if ((pSecImpl == NULL) || (! pSecImpl->m_isValid)) + return sal_False; + + strncpy(pszName, pSecImpl->m_pPasswd.pw_name, nMax); + + return sal_True; +} + +sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory) +{ + sal_Bool bRet=sal_False; + sal_Char pszDirectory[PATH_MAX]; + + pszDirectory[0] = '\0'; + + bRet = osl_psz_getHomeDir(Security,pszDirectory,sizeof(pszDirectory)); + + if ( bRet == sal_True ) + { + rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pustrDirectory != NULL); + osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory ); + } + + return bRet; +} + + +sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + /* if current user, check also environment for HOME */ + if (getuid() == pSecImpl->m_pPasswd.pw_uid) + { + sal_Char *pStr = NULL; +#ifdef SOLARIS + char buffer[8192]; + + struct passwd pwd; + struct passwd *ppwd; + +#ifdef _POSIX_PTHREAD_SEMANTICS + if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) ) + ppwd = NULL; +#else + ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) ); +#endif + + if ( ppwd ) + pStr = ppwd->pw_dir; +#else + pStr = getenv("HOME"); +#endif + + if ((pStr != NULL) && (strlen(pStr) > 0) && + (access(pStr, 0) == 0)) + strncpy(pszDirectory, pStr, nMax); + else + if (pSecImpl->m_isValid) + strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax); + else + return sal_False; + } + else + strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax); + + return sal_True; +} + +sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory) +{ + sal_Bool bRet = sal_False; + sal_Char pszDirectory[PATH_MAX]; + + pszDirectory[0] = '\0'; + + bRet = osl_psz_getConfigDir(Security,pszDirectory,sizeof(pszDirectory)); + + if ( bRet == sal_True ) + { + rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pustrDirectory != NULL); + osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory ); + } + + return bRet; +} + + +sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax) +{ + return (osl_psz_getHomeDir(Security, pszDirectory, nMax)); +} + +sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + if (pSecImpl->m_pPasswd.pw_uid != 0) + return (sal_False); + + return (sal_True); +} + +void SAL_CALL osl_freeSecurityHandle(oslSecurity Security) +{ + if (Security) + free ((oslSecurityImpl*)Security); +} + + +sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security) +{ + return sal_False; +} + +void SAL_CALL osl_unloadUserProfile(oslSecurity Security) +{ + return; +} + + diff --git a/sal/osl/os2/semaphor.c b/sal/osl/os2/semaphor.c new file mode 100644 index 000000000000..8613e3ecd352 --- /dev/null +++ b/sal/osl/os2/semaphor.c @@ -0,0 +1,190 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/semaphor.h> + +/* + Implemetation notes: + The void* represented by oslSemaphore is used + to store a OS/2 HANDLE. +*/ + +typedef struct _oslSemaphoreImpl +{ + HEV hevReachedZero; + int nCount; +} oslSemaphoreImpl; + +// static mutex to control access to private members of oslMutexImpl +static HMTX MutexLock = NULL; + +/*****************************************************************************/ +/* osl_createSemaphore */ +/*****************************************************************************/ + +/* +- Erzeugen der Semaphore +- Z„hler auf initialCount setzen +*/ +oslSemaphore SAL_CALL osl_createSemaphore(sal_uInt32 initialCount) +{ + APIRET rc; + oslSemaphoreImpl * pSemaphoreImpl; + + /* alloc mem. for our internal data structure */ + pSemaphoreImpl = (oslSemaphoreImpl *) malloc(sizeof(oslSemaphoreImpl)); + if( pSemaphoreImpl == NULL ) + return NULL; + + /* create semaphore */ + rc = DosCreateEventSem( NULL, + &pSemaphoreImpl->hevReachedZero, + DC_SEM_SHARED, + FALSE ); + if( rc != NO_ERROR ) + { + free( pSemaphoreImpl ); + return NULL; + } + + pSemaphoreImpl->nCount = initialCount; + + // create static mutex for private members + if (MutexLock == NULL) + DosCreateMutexSem( NULL, &MutexLock, 0, FALSE ); + + return (oslSemaphore) pSemaphoreImpl; +} + +/*****************************************************************************/ +/* osl_destroySemaphore */ +/*****************************************************************************/ + +/* +- Semaphore l”schen +*/ + +void SAL_CALL osl_destroySemaphore(oslSemaphore Semaphore) +{ + oslSemaphoreImpl* pSemaphoreImpl = (oslSemaphoreImpl*)Semaphore; + OSL_ASSERT(Semaphore != 0); + + DosCloseEventSem( pSemaphoreImpl->hevReachedZero ); + + free( pSemaphoreImpl ); +} + +/*****************************************************************************/ +/* osl_acquireSemaphore */ +/*****************************************************************************/ +/* +- Z„hler -1 +- wenn Z„hler < 0: blockieren +*/ + +sal_Bool SAL_CALL osl_acquireSemaphore(oslSemaphore Semaphore) +{ + APIRET rc; + oslSemaphoreImpl* pSemaphoreImpl = (oslSemaphoreImpl*)Semaphore; + int nCount; + OSL_ASSERT(Semaphore != 0); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + + while( pSemaphoreImpl->nCount < 1 ) + { + sal_uInt32 nPostCount; + + DosReleaseMutexSem( MutexLock); + + rc = DosWaitEventSem(pSemaphoreImpl->hevReachedZero, SEM_INDEFINITE_WAIT ); + DosResetEventSem(pSemaphoreImpl->hevReachedZero, &nPostCount); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + } + + pSemaphoreImpl->nCount--; + DosReleaseMutexSem( MutexLock); + + return( rc == NO_ERROR ); +} + +/*****************************************************************************/ +/* osl_tryToAcquireSemaphore */ +/*****************************************************************************/ +/* +- Z„hler -1, wenn vorher > 0 +- wenn Z„hler < 0: mit FALSE zurueck +*/ +sal_Bool SAL_CALL osl_tryToAcquireSemaphore(oslSemaphore Semaphore) +{ + APIRET rc; + oslSemaphoreImpl* pSemaphoreImpl = (oslSemaphoreImpl*)Semaphore; + int nCount; + OSL_ASSERT(Semaphore != 0); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + + nCount = pSemaphoreImpl->nCount; + if( pSemaphoreImpl->nCount > 0 ) + pSemaphoreImpl->nCount--; + + DosReleaseMutexSem( MutexLock); + + return( nCount > 0 ); +} + +/*****************************************************************************/ +/* osl_releaseSemaphore */ +/*****************************************************************************/ +/* +- Z„hler +1 +*/ +sal_Bool SAL_CALL osl_releaseSemaphore(oslSemaphore Semaphore) +{ + APIRET rc; + oslSemaphoreImpl* pSemaphoreImpl = (oslSemaphoreImpl*)Semaphore; + int nCount; + OSL_ASSERT(Semaphore != 0); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + + nCount = pSemaphoreImpl->nCount; + pSemaphoreImpl->nCount++; + + DosReleaseMutexSem( MutexLock); + + if( nCount == 0 ) + DosPostEventSem(pSemaphoreImpl->hevReachedZero); + + return( rc == NO_ERROR ); +} + + diff --git a/sal/osl/os2/signal.c b/sal/osl/os2/signal.c new file mode 100644 index 000000000000..881db13fe1e1 --- /dev/null +++ b/sal/osl/os2/signal.c @@ -0,0 +1,249 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/* system headers */ +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/mutex.h> +#include <osl/signal.h> + +typedef struct _oslSignalHandlerImpl +{ + oslSignalHandlerFunction Handler; + void* pData; + struct _oslSignalHandlerImpl* pNext; +} oslSignalHandlerImpl; + +static sal_Bool bErrorReportingEnabled = sal_True; +static sal_Bool bInitSignal = sal_False; +static oslMutex SignalListMutex; +static oslSignalHandlerImpl* SignalList; + +/*static*//* ULONG _Export APIENTRY SignalHandlerFunction(PEXCEPTIONREPORTRECORD pERepRec, + PEXCEPTIONREGISTRATIONRECORD, + PCONTEXTRECORD, PVOID); +*/ +/*static*/ ULONG __declspec(dllexport) APIENTRY SignalHandlerFunction(PEXCEPTIONREPORTRECORD pERepRec, + PEXCEPTIONREGISTRATIONRECORD, + PCONTEXTRECORD, PVOID); +static EXCEPTIONREGISTRATIONRECORD ExcptHandler = { 0, SignalHandlerFunction }; + +static sal_Bool InitSignal( void ) +{ + SignalListMutex = osl_createMutex(); + + ExcptHandler.ExceptionHandler = (_ERR *) &SignalHandlerFunction; + /* DosSetExceptionHandler(&ExcptHandler); */ + + return sal_True; +} + +static sal_Bool DeInitSignal( void ) +{ + /* DosUnsetExceptionHandler(&ExcptHandler); */ + + osl_destroyMutex(SignalListMutex); + + return sal_False; +} + +static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) +{ + oslSignalHandlerImpl* pHandler = SignalList; + oslSignalAction Action = osl_Signal_ActCallNextHdl; + + while (pHandler != NULL) + { + if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl) + break; + + pHandler = pHandler->pNext; + } + + return Action; +} + +/*****************************************************************************/ +/* SignalHandlerFunction */ +/*****************************************************************************/ +/*static*/ ULONG __declspec(dllexport) APIENTRY SignalHandlerFunction(PEXCEPTIONREPORTRECORD pERepRec, + PEXCEPTIONREGISTRATIONRECORD pERegRec, + PCONTEXTRECORD pConRec, PVOID pReserved) +{ + oslSignalInfo Info; + + Info.UserSignal = pERepRec->ExceptionNum; + Info.UserData = NULL; + + switch (pERepRec->ExceptionNum) + { + case XCPT_ACCESS_VIOLATION: + Info.Signal = osl_Signal_AccessViolation; + break; + + case XCPT_INTEGER_DIVIDE_BY_ZERO: + Info.Signal = osl_Signal_IntegerDivideByZero; + break; + + case XCPT_BREAKPOINT: + Info.Signal = osl_Signal_DebugBreak; + break; + + default: + Info.Signal = osl_Signal_System; + break; + } + + switch (CallSignalHandler(&Info)) + { + case osl_Signal_ActCallNextHdl: + return (XCPT_CONTINUE_SEARCH); + + case osl_Signal_ActAbortApp: + return (XCPT_CONTINUE_SEARCH); + + case osl_Signal_ActKillApp: + exit(255); + break; + } + + return (XCPT_CONTINUE_SEARCH); +} + +/*****************************************************************************/ +/* osl_addSignalHandler */ +/*****************************************************************************/ +oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) +{ + oslSignalHandlerImpl* pHandler; + + OSL_ASSERT(Handler != NULL); + + if (! bInitSignal) + bInitSignal = InitSignal(); + + pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl)); + + if (pHandler != NULL) + { + pHandler->Handler = Handler; + pHandler->pData = pData; + + osl_acquireMutex(SignalListMutex); + + pHandler->pNext = SignalList; + SignalList = pHandler; + + osl_releaseMutex(SignalListMutex); + + return (pHandler); + } + + return (NULL); +} + +/*****************************************************************************/ +/* osl_removeSignalHandler */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) +{ + oslSignalHandlerImpl *pHandler, *pPrevious = NULL; + + OSL_ASSERT(Handler != NULL); + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + pHandler = SignalList; + + while (pHandler != NULL) + { + if (pHandler == Handler) + { + if (pPrevious) + pPrevious->pNext = pHandler->pNext; + else + SignalList = pHandler->pNext; + + osl_releaseMutex(SignalListMutex); + + if (SignalList == NULL ) + bInitSignal = DeInitSignal(); + + free(pHandler); + + return (sal_True); + } + + pPrevious = pHandler; + pHandler = pHandler->pNext; + } + + osl_releaseMutex(SignalListMutex); + + return (sal_False); +} + +/*****************************************************************************/ +/* osl_raiseSignal */ +/*****************************************************************************/ +oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) +{ + oslSignalInfo Info; + oslSignalAction Action; + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + Info.Signal = osl_Signal_User; + Info.UserSignal = UserSignal; + Info.UserData = UserData; + + Action = CallSignalHandler(&Info); + + osl_releaseMutex(SignalListMutex); + + return (Action); +} + +/*****************************************************************************/ +/* osl_setErrorReporting */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) +{ + sal_Bool bOld = bErrorReportingEnabled; + bErrorReportingEnabled = bEnable; + + return bOld; +} + diff --git a/sal/osl/os2/socket.c b/sal/osl/os2/socket.c new file mode 100644 index 000000000000..6c171016f798 --- /dev/null +++ b/sal/osl/os2/socket.c @@ -0,0 +1,3097 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/socket.h> +#include <osl/diagnose.h> +#include <osl/mutex.h> +#include <osl/signal.h> + +#include <rtl/alloc.h> + +#include <ctype.h> +#include <sal/types.h> + +#include "sockimpl.h" + + +/* defines for poll */ +#ifdef HAVE_POLL_H +#undef HAVE_POLL_H +#endif + +#if defined(LINUX) || defined(NETBSD) || defined ( FREEBSD ) || defined (MACOSX) +#include <sys/poll.h> +#define HAVE_POLL_H +#endif /* HAVE_POLL_H */ + +#if defined(SOLARIS) +#include <poll.h> +#define HAVE_POLL_H +#endif /* SOLARIS */ + +#ifndef HAVE_POLL_H +#define POLLIN 0x0001 +#define POLLOUT 0x0002 +#define POLLPRI 0x0004 +#endif /* HAVE_POLL_H */ + + +/* defines for shutdown */ +#define SD_RECEIVE 0 +#define SD_SEND 1 +#define SD_BOTH 2 + + +/* + oslSocketAddr is a pointer to a Berkeley struct sockaddr. + I refrained from using sockaddr_in because of possible further + extensions of this socket-interface (IP-NG?). + The intention was to hide all Berkeley data-structures from + direct access past the osl-interface. + + The current implementation is internet (IP) centered. All + the constructor-functions (osl_create...) take parameters + that will probably make sense only in the IP-environment + (e.g. because of using the dotted-address-format). + + If the interface will be extended to host other protocol- + families, I expect no externally visible changes in the + existing functions. You'll probably need only new + constructor-functions who take the different address + formats into consideration (maybe a long dotted address + or whatever). +*/ + +/* _Note_ that I rely on the fact that oslSocketAddr and struct sockaddr */ +/* are the same! I don't like it very much but see no other easy way to */ +/* conceal the struct sockaddr from the eyes of the user. */ + + +#define OSL_INVALID_SOCKET -1 +#define OSL_SOCKET_ERROR -1 + + +/* Buffer size for gethostbyname */ +#define MAX_HOSTBUFFER_SIZE 2048 + +/*****************************************************************************/ +/* enum oslAddrFamily */ +/*****************************************************************************/ + +/* map */ +static unsigned long FamilyMap[]= { + AF_INET, /* osl_Socket_FamilyInet */ + AF_IPX, /* osl_Socket_FamilyIpx */ + 0 /* osl_Socket_FamilyInvalid */ +}; + +/* reverse map */ +static oslAddrFamily osl_AddrFamilyFromNative(sal_uInt32 nativeType) +{ + oslAddrFamily i= (oslAddrFamily)0; + + while(i != osl_Socket_FamilyInvalid) + { + if(FamilyMap[i] == nativeType) + return i; + i = (oslAddrFamily) ( i + 1 ); + } + + return i; +} + +/* macros */ +#define FAMILY_FROM_NATIVE(y) osl_AddrFamilyFromNative(y) +#define FAMILY_TO_NATIVE(x) (short)FamilyMap[x] + +/*****************************************************************************/ +/* enum oslProtocol */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 ProtocolMap[]= { + 0, /* osl_Socket_ProtocolIp */ + NSPROTO_IPX, /* osl_Socket_ProtocolIpx */ + NSPROTO_SPX, /* osl_Socket_ProtocolSpx */ + NSPROTO_SPXII, /* osl_Socket_ProtocolSpxII */ + 0 /* osl_Socket_ProtocolInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslProtocol osl_ProtocolFromNative(sal_uInt32 nativeType) +{ + oslProtocol i= (oslProtocol)0; + + while(i != osl_Socket_ProtocolInvalid) + { + if(ProtocolMap[i] == nativeType) + return i; + i = (oslProtocol) ( i + 1); + } + + return i; +} +*/ + +/* macros */ +#define PROTOCOL_FROM_NATIVE(y) osl_ProtocolFromNative(y) +#define PROTOCOL_TO_NATIVE(x) ProtocolMap[x] + + +/*****************************************************************************/ +/* enum oslSocketType */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 TypeMap[]= { + SOCK_STREAM, /* osl_Socket_TypeStream */ + SOCK_DGRAM, /* osl_Socket_TypeDgram */ + SOCK_RAW, /* osl_Socket_TypeRaw */ + SOCK_RDM, /* osl_Socket_TypeRdm */ + SOCK_SEQPACKET, /* osl_Socket_TypeSeqPacket */ + 0 /* osl_Socket_TypeInvalid */ +}; + +/* reverse map */ +static oslSocketType osl_SocketTypeFromNative(sal_uInt32 nativeType) +{ + oslSocketType i= (oslSocketType)0; + + while(i != osl_Socket_TypeInvalid) + { + if(TypeMap[i] == nativeType) + return i; + i = (oslSocketType)(i + 1); + } + + return i; +} + +/* macros */ +#define TYPE_TO_NATIVE(x) TypeMap[x] +#define TYPE_FROM_NATIVE(y) osl_SocketTypeFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketOption */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 OptionMap[]= { + SO_DEBUG, /* osl_Socket_OptionDebug */ + SO_ACCEPTCONN, /* osl_Socket_OptionAcceptConn */ + SO_REUSEADDR, /* osl_Socket_OptionReuseAddr */ + SO_KEEPALIVE, /* osl_Socket_OptionKeepAlive */ + SO_DONTROUTE, /* osl_Socket_OptionDontRoute */ + SO_BROADCAST, /* osl_Socket_OptionBroadcast */ + SO_USELOOPBACK, /* osl_Socket_OptionUseLoopback */ + SO_LINGER, /* osl_Socket_OptionLinger */ + SO_OOBINLINE, /* osl_Socket_OptionOOBinLine */ + SO_SNDBUF, /* osl_Socket_OptionSndBuf */ + SO_RCVBUF, /* osl_Socket_OptionRcvBuf */ + SO_SNDLOWAT, /* osl_Socket_OptionSndLowat */ + SO_RCVLOWAT, /* osl_Socket_OptionRcvLowat */ + SO_SNDTIMEO, /* osl_Socket_OptionSndTimeo */ + SO_RCVTIMEO, /* osl_Socket_OptionRcvTimeo */ + SO_ERROR, /* osl_Socket_OptionError */ + SO_TYPE, /* osl_Socket_OptionType */ + TCP_NODELAY, /* osl_Socket_OptionTcpNoDelay */ + 0 /* osl_Socket_OptionInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketOption osl_SocketOptionFromNative(sal_uInt32 nativeType) +{ + oslSocketOption i= (oslSocketOption)0; + + while(i != osl_Socket_OptionInvalid) + { + if(OptionMap[i] == nativeType) + return i; + i = (oslSocketOption) ( i + 1 ); + } + + return i; +} +*/ +/* macros */ +#define OPTION_TO_NATIVE(x) OptionMap[x] +#define OPTION_FROM_NATIVE(y) osl_SocketOptionFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketOptionLevel */ +/*****************************************************************************/ + +static sal_uInt32 OptionLevelMap[]= { + SOL_SOCKET, /* osl_Socket_LevelSocket */ + IPPROTO_TCP, /* osl_Socket_LevelTcp */ + 0 /* osl_Socket_LevelInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketOptionLevel osl_SocketOptionLevelFromNative(sal_uInt32 nativeType) +{ + oslSocketOptionLevel i= (oslSocketOptionLevel)0; + + while(i != osl_Socket_LevelInvalid) + { + if(OptionLevelMap[i] == nativeType) + return i; + i = (oslSocketOptionLevel) ( i + 1 ); + } + + return i; +} +*/ +/* macros */ +#define OPTION_LEVEL_TO_NATIVE(x) OptionLevelMap[x] +#define OPTION_LEVEL_FROM_NATIVE(y) osl_SocketOptionLevelFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketMsgFlag */ +/*****************************************************************************/ + +static sal_uInt32 SocketMsgFlagMap[]= { + 0, /* osl_Socket_MsgNormal */ + MSG_OOB, /* osl_Socket_MsgOOB */ + MSG_PEEK, /* osl_Socket_MsgPeek */ + MSG_DONTROUTE, /* osl_Socket_MsgDontRoute */ + MSG_MAXIOVLEN, /* osl_Socket_MsgMaxIOVLen */ + 0 /* osl_Socket_MsgInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketMsgFlag osl_SocketMsgFlagFromNative(sal_uInt32 nativeType) +{ + oslSocketMsgFlag i= (oslSocketMsgFlag)0; + + while(i != osl_Socket_MsgInvalid) + { + if(SocketMsgFlagMap[i] == nativeType) + return i; + i = (oslSocketMsgFlag) ( i + 1 ); + } + + return i; +} +*/ + +/* macros */ +#define MSG_FLAG_TO_NATIVE(x) SocketMsgFlagMap[x] +#define MSG_FLAG_FROM_NATIVE(y) osl_SocketMsgFlagFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketDirection */ +/*****************************************************************************/ + +static sal_uInt32 SocketDirection[]= { + SD_RECEIVE, /* osl_Socket_DirRead */ + SD_SEND, /* osl_Socket_DirWrite */ + SD_BOTH, /* osl_Socket_DirReadWrite */ + 0 /* osl_Socket_DirInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketDirection osl_SocketDirectionFromNative(sal_uInt32 nativeType) +{ + oslSocketDirection i= (oslSocketDirection)0; + + while(i != osl_Socket_DirInvalid) + { + if(SocketDirection[i] == nativeType) + return i; + i = (oslSocketDirection) ( i + 1 ); + } + + return i; +} +*/ + +/* macros */ +#define DIRECTION_TO_NATIVE(x) SocketDirection[x] +#define DIRECTION_FROM_NATIVE(y) osl_SocketDirectionFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketError */ +/*****************************************************************************/ + +static struct +{ + int errcode; + oslSocketError error; +} SocketError[]= { + { 0, osl_Socket_E_None }, /* no error */ + { ENOTSOCK, osl_Socket_E_NotSocket }, /* Socket operation on non-socket */ + { EDESTADDRREQ, osl_Socket_E_DestAddrReq }, /* Destination address required */ + { EMSGSIZE, osl_Socket_E_MsgSize }, /* Message too long */ + { EPROTOTYPE, osl_Socket_E_Prototype }, /* Protocol wrong type for socket */ + { ENOPROTOOPT, osl_Socket_E_NoProtocol }, /* Protocol not available */ + { EPROTONOSUPPORT, osl_Socket_E_ProtocolNoSupport }, /* Protocol not supported */ + { ESOCKTNOSUPPORT, osl_Socket_E_TypeNoSupport }, /* Socket type not supported */ + { EOPNOTSUPP, osl_Socket_E_OpNotSupport }, /* Operation not supported on socket */ + { EPFNOSUPPORT, osl_Socket_E_PfNoSupport }, /* Protocol family not supported */ + { EAFNOSUPPORT, osl_Socket_E_AfNoSupport }, /* Address family not supported by */ + /* protocol family */ + { EADDRINUSE, osl_Socket_E_AddrInUse }, /* Address already in use */ + { EADDRNOTAVAIL, osl_Socket_E_AddrNotAvail }, /* Can't assign requested address */ + { ENETDOWN, osl_Socket_E_NetDown }, /* Network is down */ + { ENETUNREACH, osl_Socket_E_NetUnreachable }, /* Network is unreachable */ + { ENETRESET, osl_Socket_E_NetReset }, /* Network dropped connection because */ + /* of reset */ + { ECONNABORTED, osl_Socket_E_ConnAborted }, /* Software caused connection abort */ + { ECONNRESET, osl_Socket_E_ConnReset }, /* Connection reset by peer */ + { ENOBUFS, osl_Socket_E_NoBufferSpace }, /* No buffer space available */ + { EISCONN, osl_Socket_E_IsConnected }, /* Socket is already connected */ + { ENOTCONN, osl_Socket_E_NotConnected }, /* Socket is not connected */ + { ESHUTDOWN, osl_Socket_E_Shutdown }, /* Can't send after socket shutdown */ + { ETOOMANYREFS, osl_Socket_E_TooManyRefs }, /* Too many references: can't splice */ + { ETIMEDOUT, osl_Socket_E_TimedOut }, /* Connection timed out */ + { ECONNREFUSED, osl_Socket_E_ConnRefused }, /* Connection refused */ + { EHOSTDOWN, osl_Socket_E_HostDown }, /* Host is down */ + { EHOSTUNREACH, osl_Socket_E_HostUnreachable }, /* No route to host */ + { EWOULDBLOCK, osl_Socket_E_WouldBlock }, /* call would block on non-blocking socket */ + { EALREADY, osl_Socket_E_Already }, /* operation already in progress */ + { EINPROGRESS, osl_Socket_E_InProgress }, /* operation now in progress */ + { EAGAIN, osl_Socket_E_WouldBlock }, /* same as EWOULDBLOCK */ + { -1, osl_Socket_E_InvalidError } +}; + +/* map */ +/* mfe: NOT USED +static int osl_NativeFromSocketError(oslSocketError errorCode) +{ + int i = 0; + + while ((SocketError[i].error != osl_Socket_E_InvalidError) && + (SocketError[i].error != errorCode)) i++; + + return SocketError[i].errcode; +} +*/ + +/* reverse map */ +static oslSocketError osl_SocketErrorFromNative(int nativeType) +{ + int i = 0; + + while ((SocketError[i].error != osl_Socket_E_InvalidError) && + (SocketError[i].errcode != nativeType)) i++; + + return SocketError[i].error; +} + +/* macros */ +#define ERROR_TO_NATIVE(x) osl_NativeFromSocketError(x) +#define ERROR_FROM_NATIVE(y) osl_SocketErrorFromNative(y) + +/*****************************************************************************/ +/* local function prototypes */ +/*****************************************************************************/ + +oslSocketAddr SAL_CALL osl_psz_createInetSocketAddr ( + const sal_Char* pszDottedAddr, sal_Int32 Port); + +oslSocketAddr SAL_CALL osl_psz_createIpxSocketAddr ( + const sal_Char NetNumber[4], + const sal_Char NodeNumber[6], + sal_uInt32 SocketNumber); + +oslHostAddr SAL_CALL osl_psz_createHostAddr ( + const sal_Char *pszHostname, const oslSocketAddr Addr); + +oslHostAddr SAL_CALL osl_psz_createHostAddrByName ( + const sal_Char *pszHostname); + +const sal_Char* SAL_CALL osl_psz_getHostnameOfHostAddr ( + const oslHostAddr Addr); + +oslSocketResult SAL_CALL osl_psz_getLocalHostname ( + sal_Char *pBuffer, sal_uInt32 nBufLen); + +oslSocketAddr SAL_CALL osl_psz_resolveHostname ( + const sal_Char* pszHostname); + +sal_Int32 SAL_CALL osl_psz_getServicePort ( + const sal_Char* pszServicename, const sal_Char* pszProtocol); + +oslSocketResult SAL_CALL osl_psz_getHostnameOfSocketAddr ( + oslSocketAddr Addr, sal_Char *pBuffer, sal_uInt32 BufferSize); + +oslSocketResult SAL_CALL osl_psz_getDottedInetAddrOfSocketAddr ( + oslSocketAddr Addr, sal_Char *pBuffer, sal_uInt32 BufferSize); + +void SAL_CALL osl_psz_getLastSocketErrorDescription ( + oslSocket Socket, sal_Char* pBuffer, sal_uInt32 BufferSize); + +/*****************************************************************************/ +/* osl_create/destroy-SocketImpl */ +/*****************************************************************************/ + +#if OSL_DEBUG_LEVEL > 1 +static sal_uInt32 g_nSocketImpl = 0; +static sal_uInt32 g_nSocketAddr = 0; + +/* sorry, must be implemented otherwise */ +#if 0 +struct LeakWarning +{ + ~LeakWarning() + { + if( g_nSocketImpl ) + OSL_TRACE( "sal_socket: %d socket instances leak\n" , g_nSocketImpl ); + if( g_nSocketAddr ) + OSL_TRACE( "sal_socket: %d socket address instances leak\n" , g_nSocketAddr ); + } +}; +LeakWarning socketWarning; +#endif + +#endif /* OSL_DEBUG_LEVEL */ + + +oslSocket __osl_createSocketImpl(int Socket) +{ + oslSocket pSocket; + + pSocket = (oslSocket)calloc(1, sizeof(struct oslSocketImpl)); + + pSocket->m_Socket = Socket; + pSocket->m_nLastError = 0; + pSocket->m_CloseCallback = 0; + pSocket->m_CallbackArg = 0; + pSocket->m_nRefCount = 1; + +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_False; +#endif + +#if OSL_DEBUG_LEVEL > 1 + g_nSocketImpl ++; +#endif + return pSocket; +} + +void __osl_destroySocketImpl(oslSocket Socket) +{ + if ( Socket != NULL) + free((struct oslSocketImpl *) Socket); +#if OSL_DEBUG_LEVEL > 1 + g_nSocketImpl --; +#endif +} + +static oslSocketAddr __osl_createSocketAddr( ) +{ + oslSocketAddr pAddr = (oslSocketAddr) rtl_allocateZeroMemory( sizeof( struct oslSocketAddrImpl )); +#if OSL_DEBUG_LEVEL > 1 + g_nSocketAddr ++; +#endif + return pAddr; +} + +static oslSocketAddr __osl_createSocketAddrWithFamily( + oslAddrFamily family, sal_Int32 port, sal_uInt32 nAddr ) +{ + oslSocketAddr pAddr; + + OSL_ASSERT( family == osl_Socket_FamilyInet ); + + pAddr = __osl_createSocketAddr(); + switch( family ) + { + case osl_Socket_FamilyInet: + { + struct sockaddr_in* pInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + pInetAddr->sin_family = FAMILY_TO_NATIVE(osl_Socket_FamilyInet); + pInetAddr->sin_addr.s_addr = nAddr; + pInetAddr->sin_port = (sal_uInt16)(port&0xffff); + break; + } + default: + pAddr->m_sockaddr.sa_family = FAMILY_TO_NATIVE(family); + } + return pAddr; +} + +static oslSocketAddr __osl_createSocketAddrFromSystem( struct sockaddr *pSystemSockAddr ) +{ + oslSocketAddr pAddr = __osl_createSocketAddr(); + memcpy( &(pAddr->m_sockaddr), pSystemSockAddr, sizeof( struct sockaddr ) ); + return pAddr; +} + +static void __osl_destroySocketAddr( oslSocketAddr addr ) +{ +#if OSL_DEBUG_LEVEL > 1 + g_nSocketAddr --; +#endif + rtl_freeMemory( addr ); +} + +/*****************************************************************************/ +/* osl_createEmptySocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createEmptySocketAddr(oslAddrFamily Family) +{ + oslSocketAddr pAddr = 0; + + /* is it an internet-Addr? */ + if (Family == osl_Socket_FamilyInet) + { + pAddr = __osl_createSocketAddrWithFamily(Family, 0 , htonl(INADDR_ANY) ); + } + else + { + pAddr = __osl_createSocketAddrWithFamily( Family , 0 , 0 ); + } + + return pAddr; +} + +/*****************************************************************************/ +/* osl_copySocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_copySocketAddr(oslSocketAddr Addr) +{ + oslSocketAddr pCopy = 0; + if (Addr) + { + pCopy = __osl_createSocketAddr(); + + if (pCopy) + memcpy(&(pCopy->m_sockaddr),&(Addr->m_sockaddr), sizeof(struct sockaddr)); + } + return pCopy; +} + +/*****************************************************************************/ +/* osl_isEqualSocketAddr */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isEqualSocketAddr ( + oslSocketAddr Addr1, + oslSocketAddr Addr2) +{ + struct sockaddr* pAddr1= &(Addr1->m_sockaddr); + struct sockaddr* pAddr2= &(Addr2->m_sockaddr); + + OSL_ASSERT(pAddr1); + OSL_ASSERT(pAddr2); + + if (pAddr1->sa_family == pAddr2->sa_family) + { + switch (pAddr1->sa_family) + { + case AF_INET: + { + struct sockaddr_in* pInetAddr1= (struct sockaddr_in*)pAddr1; + struct sockaddr_in* pInetAddr2= (struct sockaddr_in*)pAddr2; + + if ((pInetAddr1->sin_family == pInetAddr2->sin_family) && + (pInetAddr1->sin_addr.s_addr == pInetAddr2->sin_addr.s_addr) && + (pInetAddr1->sin_port == pInetAddr2->sin_port)) + return (sal_True); + } + + default: + { + return (memcmp(pAddr1, Addr2, sizeof(struct sockaddr)) == 0); + } + } + } + + return (sal_False); +} + +/*****************************************************************************/ +/* osl_createInetBroadcastAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createInetBroadcastAddr ( + rtl_uString *strDottedAddr, + sal_Int32 Port) +{ + sal_uInt32 nAddr = OSL_INADDR_NONE; + oslSocketAddr pAddr; + + if (strDottedAddr && strDottedAddr->length) + { + /* Dotted host address for limited broadcast */ + rtl_String *pDottedAddr = NULL; + + rtl_uString2String ( + &pDottedAddr, strDottedAddr->buffer, strDottedAddr->length, + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + + nAddr = inet_addr (pDottedAddr->buffer); + rtl_string_release (pDottedAddr); + } + + if (nAddr != OSL_INADDR_NONE) + { + /* Limited broadcast */ + nAddr = ntohl(nAddr); + if (IN_CLASSA(nAddr)) + { + nAddr &= IN_CLASSA_NET; + nAddr |= IN_CLASSA_HOST; + } + else if (IN_CLASSB(nAddr)) + { + nAddr &= IN_CLASSB_NET; + nAddr |= IN_CLASSB_HOST; + } + else if (IN_CLASSC(nAddr)) + { + nAddr &= IN_CLASSC_NET; + nAddr |= IN_CLASSC_HOST; + } + else + { + /* No broadcast in class D */ + return ((oslSocketAddr)NULL); + } + nAddr = htonl(nAddr); + } + + pAddr = __osl_createSocketAddrWithFamily( osl_Socket_FamilyInet, htons(Port), nAddr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_createInetSocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createInetSocketAddr ( + rtl_uString *ustrDottedAddr, + sal_Int32 Port) +{ + rtl_String* strDottedAddr=0; + oslSocketAddr Addr; + sal_Char* pszDottedAddr=0; + + if ( ustrDottedAddr != 0 ) + { + rtl_uString2String( &strDottedAddr, + rtl_uString_getStr(ustrDottedAddr), + rtl_uString_getLength(ustrDottedAddr), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS); + pszDottedAddr = rtl_string_getStr(strDottedAddr); + } + + + Addr = osl_psz_createInetSocketAddr(pszDottedAddr, Port); + + if ( strDottedAddr != 0 ) + { + rtl_string_release(strDottedAddr); + } + + return Addr; +} + +oslSocketAddr SAL_CALL osl_psz_createInetSocketAddr ( + const sal_Char* pszDottedAddr, + sal_Int32 Port) +{ + oslSocketAddr pAddr = 0; + sal_Int32 Addr = inet_addr(pszDottedAddr); + if(Addr != -1) + { + /* valid dotted addr */ + pAddr = __osl_createSocketAddrWithFamily( osl_Socket_FamilyInet, htons(Port) , Addr ); + } + return pAddr; +} + +/*****************************************************************************/ +/* osl_setAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_setAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence *pByteSeq ) +{ + oslSocketResult res = osl_Socket_Error; + + OSL_ASSERT( pAddr ); + OSL_ASSERT( pByteSeq ); + + if( pAddr && pByteSeq ) + { + struct sockaddr_in * pSystemInetAddr; + + OSL_ASSERT( pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE( osl_Socket_FamilyInet ) ); + OSL_ASSERT( pByteSeq->nElements == 4 ); + + pSystemInetAddr = (struct sockaddr_in * ) &(pAddr->m_sockaddr); + memcpy( &(pSystemInetAddr->sin_addr) , pByteSeq->elements , 4 ); + res = osl_Socket_Ok; + } + return res; +} + +/*****************************************************************************/ +/* osl_getAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence **ppByteSeq ) +{ + oslSocketResult res = osl_Socket_Error; + + OSL_ASSERT( pAddr ); + OSL_ASSERT( ppByteSeq ); + + if( pAddr && ppByteSeq ) + { + struct sockaddr_in * pSystemInetAddr = (struct sockaddr_in * ) &(pAddr->m_sockaddr); + rtl_byte_sequence_constructFromArray( ppByteSeq , (sal_Int8 *) &(pSystemInetAddr->sin_addr),4); + res = osl_Socket_Ok; + } + return res; +} + + +/*****************************************************************************/ +/* _osl_getFullQualifiedDomainName */ +/*****************************************************************************/ + +/** try to figure out a full-qualified hostname, by adding the current domain + as given by the domainname program to the given hostname. + This function MUST NOT call gethostbyname since pHostName allready points + to data returned by gethostname and would be garbled: use gethostname_r + instead! + */ + +/* wrap around different interfaces to reentrant gethostbyname */ +static struct hostent* _osl_gethostbyname_r ( + const char *name, struct hostent *result, + char *buffer, int buflen, int *h_errnop) +{ + +#ifdef LINUX + struct hostent *__result; /* will be the same as result */ + int __error; + __error = gethostbyname_r (name, result, buffer, buflen, + &__result, h_errnop); + return __error ? NULL : __result ; +#elif defined OS2 + // YD FIXME!!! + return 0; +#else + return gethostbyname_r( name, result, buffer, buflen, h_errnop); +#endif +} + +static sal_Bool _osl_getDomainName (sal_Char *buffer, sal_Int32 bufsiz) +{ + sal_Bool result; + int p[2]; + + result = sal_False; + +#if 0 // YD 17/04/06 libc panic for fork() from thread!=1 + + if (pipe (p) == 0) + { + pid_t pid; + int nStatus; + + pid = fork(); + if (pid == 0) + { + char *argv[] = + { + "/bin/domainname", + NULL + }; + + close (p[0]); + dup2 (p[1], 1); + close (p[1]); + + execv ("/bin/domainname", argv); + // arriving here means exec failed + _exit(-1); + } + else if (pid > 0) + { + sal_Int32 k = 0, n = bufsiz; + + close (p[1]); + if ((k = read (p[0], buffer, n - 1)) > 0) + { + buffer[k] = 0; + if (buffer[k - 1] == '\n') + buffer[k - 1] = 0; + result = sal_True; + } + close (p[0]); + waitpid (pid, &nStatus, 0); + } + else + { + close (p[0]); + close (p[1]); + } + } +#endif // 0 + + return (result); +} + +static sal_Char* _osl_getFullQualifiedDomainName (const sal_Char *pHostName) +{ +# define DOMAINNAME_LENGTH 512 + sal_uInt32 nLengthOfHostName; + static sal_uInt32 nLengthOfDomainName = 0; + static sal_Char *pDomainName = NULL; + + sal_Char *pFullQualifiedName; +#if 0 /* OBSOLETE */ + FILE *pPipeToDomainnameExe; +#endif /* OBSOLETE */ + + /* get a '\0' terminated domainname */ + + /* read default domainname default from environment */ + if (nLengthOfDomainName == 0) + { + sal_Char *pEnvDomain; + + pEnvDomain = getenv ("STAR_OVERRIDE_DOMAINNAME"); + if (pEnvDomain) + { + pDomainName = strdup (pEnvDomain); + nLengthOfDomainName = strlen (pDomainName); + } + } + +#if 1 /* NEW */ + if (nLengthOfDomainName == 0) + { + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + + pDomainNameBuffer[0] = '\0'; + + if (_osl_getDomainName (pDomainNameBuffer, DOMAINNAME_LENGTH)) + { + pDomainName = strdup (pDomainNameBuffer); + nLengthOfDomainName = strlen (pDomainName); + } + } + +#endif /* NEW */ +#if 0 /* OBSOLETE */ +#ifdef SCO + + /* call 'domainname > /usr/tmp/some-tmp-file', since + popen read pclose do block or core-dump, + (even the pipe-stuff that comes with pthreads) */ + if (nLengthOfDomainName == 0) + { + sal_Char tmp_name[ L_tmpnam ]; + FILE *tmp_file; + sal_Char domain_call [ L_tmpnam + 16 ] = "domainname > "; + + tmp_name[0] = '\0'; + + tmpnam ( tmp_name ); + strcat ( domain_call, tmp_name ); + if ( (system ( domain_call ) == 0) + && ((tmp_file = fopen( tmp_name, "r" )) != NULL ) ) + { + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + + pDomainNameBuffer[0] = '\0'; + + if ( fgets ( pDomainNameBuffer, DOMAINNAME_LENGTH, tmp_file ) ) + { + pDomainName = strdup( pDomainNameBuffer ); + nLengthOfDomainName = strlen( pDomainName ); + if ( ( nLengthOfDomainName > 0 ) + && ( pDomainName[ nLengthOfDomainName - 1] == '\n' ) ) + pDomainName[ --nLengthOfDomainName ] = '\0'; + } + fclose ( tmp_file ); + } + unlink( tmp_name ); + } + +#else /* !SCO */ + + /* read the domainname from pipe to the program domainname */ + if ( (nLengthOfDomainName == 0) + && (pPipeToDomainnameExe = popen( "domainname", "r")) ) + { + sal_Char c; + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + sal_Char *pDomainNamePointer; + + pDomainNameBuffer[0] = '\0'; + + pDomainNamePointer = pDomainNameBuffer; + while ( ((c = getc( pPipeToDomainnameExe )) != EOF) + && (nLengthOfDomainName < (DOMAINNAME_LENGTH - 1)) ) + { + if (! isspace(c)) + { + nLengthOfDomainName++ ; + *pDomainNamePointer++ = (sal_Char)c; + } + } + *pDomainNamePointer = '\0'; + pDomainName = strdup( pDomainNameBuffer ); + + pclose( pPipeToDomainnameExe ); + } + +#endif /* !SCO */ +#endif /* OBSOLETE */ + + /* compose hostname and domainname */ + nLengthOfHostName = strlen( pHostName ); + pFullQualifiedName = (sal_Char*) malloc( (nLengthOfHostName + 1 + + nLengthOfDomainName + 1) * sizeof(sal_Char) ); + memcpy( pFullQualifiedName, pHostName, + (nLengthOfHostName + 1) * sizeof(sal_Char) ); + + if ( nLengthOfDomainName > 0 ) + { + /* fqdn = hostname + '.' + domainname + '\0' */ + pFullQualifiedName[ nLengthOfHostName ] = '.'; + memcpy( pFullQualifiedName + nLengthOfHostName + 1, pDomainName, + nLengthOfDomainName + 1 ); + } + + /* check whether full-qualified name and hostname point to the same host + * should almost always be true */ + if ( nLengthOfDomainName > 0 ) + { + struct hostent *pQualifiedHostByName; + struct hostent *pHostByName; + sal_Bool bHostsAreEqual; + + /* buffer for calls to reentrant version of gethostbyname */ + struct hostent aHostByName, aQualifiedHostByName; + sal_Char pHostBuffer[ MAX_HOSTBUFFER_SIZE ]; + sal_Char pQualifiedHostBuffer[ MAX_HOSTBUFFER_SIZE ]; + int nErrorNo; + + pHostBuffer[0] = '\0'; + pQualifiedHostBuffer[0] = '\0'; + + /* get list of addresses */ + pQualifiedHostByName = _osl_gethostbyname_r ( + pFullQualifiedName, + &aQualifiedHostByName, pQualifiedHostBuffer, + sizeof(pQualifiedHostBuffer), &nErrorNo ); + pHostByName = _osl_gethostbyname_r ( + pHostName, + &aHostByName, pHostBuffer, + sizeof(pHostBuffer), &nErrorNo ); + + /* compare addresses */ + bHostsAreEqual = sal_False; + if ( pQualifiedHostByName && pHostByName ) + { + sal_Char **p, **q; + struct in_addr in; + + /* lists are expected to be (very) short */ + for ( p = pQualifiedHostByName->h_addr_list; *p != NULL; p++ ) + { + for ( q = pHostByName->h_addr_list; *q != NULL; q++ ) + { + /* in.s_addr may be in_addr_t or uint32_t or heaven knows */ + if ( memcmp( *p, *q, sizeof(in.s_addr) ) == 0 ) + { + bHostsAreEqual = sal_True; + break; + } + } + if ( bHostsAreEqual ) + break; + } + } + + /* very strange case, but have to believe it: reduce the + * full qualified name to the unqualified host name */ + if ( !bHostsAreEqual ) + { + OSL_TRACE("_osl_getFullQualifiedDomainName: " + "suspect FQDN: %s\n", pFullQualifiedName); + + pFullQualifiedName[ nLengthOfHostName ] = '\0'; + pFullQualifiedName = (sal_Char*)realloc ( pFullQualifiedName, + (nLengthOfHostName + 1) * sizeof( sal_Char )); + } + } + + /* always return a hostname looked up as carefully as possible + * this string must be freed by the caller */ + return pFullQualifiedName; +} + +/*****************************************************************************/ +/* _osl_isFullQualifiedDomainName */ +/*****************************************************************************/ +static sal_Bool _osl_isFullQualifiedDomainName (const sal_Char *pHostName) +{ + /* a FQDN (aka 'hostname.domain.top_level_domain' ) + * is a name which contains a dot '.' in it ( would + * match as well for 'hostname.' but is good enough + * for now )*/ + return (sal_Bool)( strchr( pHostName, (int)'.' ) != NULL ); +} + +/*****************************************************************************/ +/* oslHostAddr */ +/*****************************************************************************/ +struct oslHostAddrImpl +{ + sal_Char *pHostName; + oslSocketAddr pSockAddr; +}; + +static oslHostAddr _osl_hostentToHostAddr (const struct hostent *he) +{ + oslHostAddr pAddr= NULL; + oslSocketAddr pSockAddr = 0; + + + if ((he == NULL) || (he->h_name == NULL) || (he->h_addr_list[0] == NULL)) + return ((oslHostAddr)NULL); + + //YD 18/06/2006 win32 does this with unicode, see socket.cxx + sal_Char *cn; + cn= (sal_Char *)malloc(strlen (he->h_name) + 1); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + + strcpy(cn, he->h_name); + +#if 0 // YD 17/04/06 win32 doesn't it. + if (_osl_isFullQualifiedDomainName(he->h_name)) + { + cn= (sal_Char *)malloc(strlen (he->h_name) + 1); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + + strcpy(cn, he->h_name); + } + else + { + cn =_osl_getFullQualifiedDomainName (he->h_name); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + } +#endif + + pSockAddr = __osl_createSocketAddr(); + OSL_ASSERT(pSockAddr); + if (pSockAddr == NULL) + { + free(cn); + return ((oslHostAddr)NULL); + } + + pSockAddr->m_sockaddr.sa_family= he->h_addrtype; + if (pSockAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + struct sockaddr_in *sin= (struct sockaddr_in *)&(pSockAddr->m_sockaddr); + memcpy ( + &(sin->sin_addr.s_addr), + he->h_addr_list[0], + he->h_length); + } + else + { + /* unknown address family */ + /* future extensions for new families might be implemented here */ + + OSL_TRACE("_osl_hostentToHostAddr: unknown address family.\n"); + OSL_ASSERT(sal_False); + + __osl_destroySocketAddr( pSockAddr ); + free (cn); + return ((oslHostAddr)NULL); + } + + pAddr= (oslHostAddr) malloc(sizeof(struct oslHostAddrImpl)); + OSL_ASSERT(pAddr); + if (pAddr == NULL) + { + __osl_destroySocketAddr( pSockAddr ); + free (cn); + return ((oslHostAddr)NULL); + } + + pAddr->pHostName= cn; + pAddr->pSockAddr= pSockAddr; + + return pAddr; +} + +/*****************************************************************************/ +/* osl_createHostAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddr ( + rtl_uString *ustrHostname, + const oslSocketAddr Addr) +{ + oslHostAddr HostAddr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName = rtl_string_getStr(strHostname); + } + + HostAddr = osl_psz_createHostAddr(pszHostName,Addr); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + + return HostAddr; +} + +oslHostAddr SAL_CALL osl_psz_createHostAddr ( + const sal_Char *pszHostname, + const oslSocketAddr pAddr) +{ + oslHostAddr pHostAddr; + sal_Char *cn; + + OSL_ASSERT(pszHostname && pAddr); + if ((pszHostname == NULL) || (pAddr == NULL)) + return ((oslHostAddr)NULL); + + cn = (sal_Char *)malloc(strlen (pszHostname) + 1); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + + strcpy (cn, pszHostname); + + pHostAddr= (oslHostAddr) malloc(sizeof(struct oslHostAddrImpl)); + OSL_ASSERT(pHostAddr); + if (pAddr == NULL) + { + free (cn); + return ((oslHostAddr)NULL); + } + + pHostAddr->pHostName= cn; + pHostAddr->pSockAddr= osl_copySocketAddr( pAddr ); + + return pHostAddr; +} + +/*****************************************************************************/ +/* osl_createHostAddrByName */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddrByName(rtl_uString *ustrHostname) +{ + oslHostAddr HostAddr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName=rtl_string_getStr(strHostname); + } + + HostAddr = osl_psz_createHostAddrByName(pszHostName); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + return HostAddr; +} + +oslHostAddr SAL_CALL osl_psz_createHostAddrByName (const sal_Char *pszHostname) +{ + struct hostent *he; + oslHostAddr addr; + + static oslMutex mutex = NULL; + + if (mutex == NULL) + mutex = osl_createMutex(); + + osl_acquireMutex(mutex); + + he = gethostbyname((sal_Char *)pszHostname); + addr = _osl_hostentToHostAddr (he); + + osl_releaseMutex(mutex); + + return addr; +} + +/*****************************************************************************/ +/* osl_createHostAddrByAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddrByAddr (const oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr == NULL) + return ((oslHostAddr)NULL); + + if (pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + const struct sockaddr_in *sin= (const struct sockaddr_in *)&(pAddr->m_sockaddr); + struct hostent *he; + + if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) + return ((oslHostAddr)NULL); + + he= gethostbyaddr((sal_Char *)&(sin->sin_addr), + sizeof (sin->sin_addr), + sin->sin_family); + return _osl_hostentToHostAddr (he); + } + + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_copyHostAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_copyHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return osl_psz_createHostAddr (pAddr->pHostName, pAddr->pSockAddr); + else + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_getHostnameOfHostAddr */ +/*****************************************************************************/ +void SAL_CALL osl_getHostnameOfHostAddr ( + const oslHostAddr Addr, + rtl_uString **ustrHostname) +{ + const sal_Char* pHostname=0; + + pHostname = osl_psz_getHostnameOfHostAddr(Addr); + + rtl_uString_newFromAscii (ustrHostname, pHostname); + + return; +} + +const sal_Char* SAL_CALL osl_psz_getHostnameOfHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return pAddr->pHostName; + else + return NULL; +} + +/*****************************************************************************/ +/* osl_getSocketAddrOfHostAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getSocketAddrOfHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return ((oslSocketAddr)(pAddr->pSockAddr)); + else + return NULL; +} + +/*****************************************************************************/ +/* osl_destroyHostAddr */ +/*****************************************************************************/ +void SAL_CALL osl_destroyHostAddr (oslHostAddr pAddr) +{ + if (pAddr) + { + if (pAddr->pHostName) + free (pAddr->pHostName); + if (pAddr->pSockAddr) + osl_destroySocketAddr (pAddr->pSockAddr); + free (pAddr); + } +} + +/*****************************************************************************/ +/* osl_getLocalHostname */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getLocalHostname(rtl_uString **ustrLocalHostname) +{ + oslSocketResult Result; + sal_Char pszHostname[1024]; + + pszHostname[0] = '\0'; + + Result = osl_psz_getLocalHostname(pszHostname,sizeof(pszHostname)); + + rtl_uString_newFromAscii(ustrLocalHostname,pszHostname); + + return Result; +} + +oslSocketResult SAL_CALL osl_psz_getLocalHostname ( + sal_Char *pBuffer, sal_uInt32 nBufLen) +{ + static sal_Char LocalHostname[256] = ""; + + if (strlen(LocalHostname) == 0) + { + const sal_Char *pStr; + +#ifdef SYSV + struct utsname uts; + + if (uname(&uts) < 0) + return osl_Socket_Error; + + if ((strlen(uts.nodename) + 1) > nBufLen) + return osl_Socket_Error; + + strncpy(LocalHostname, uts.nodename, sizeof( LocalHostname )); +#else /* BSD compatible */ + + if (gethostname(LocalHostname, sizeof(LocalHostname)-1) != 0) + return osl_Socket_Error; + LocalHostname[sizeof(LocalHostname)-1] = 0; +#endif /* SYSV */ + + /* check if we have an FQDN */ + if (strchr(LocalHostname, '.') == NULL) + { + oslHostAddr Addr; + + /* no, determine it via dns */ + Addr = osl_psz_createHostAddrByName(LocalHostname); + + if (Addr && (pStr = osl_psz_getHostnameOfHostAddr(Addr)) != NULL) + { +#if 0 /* OBSOLETE */ + sal_Char* pChr; +#endif /* OBSOLETE */ + strcpy(LocalHostname, pStr); + +#if 0 /* OBSOLETE */ + /* already done by _osl_getFullQualifiedDomainName() with + much better heuristics, so this may be contraproductive */ + + /* no FQDN, last try append domain name */ + if ((pChr = strchr(LocalHostname, '.')) == NULL) + { + FILE *fp; + + pChr = &LocalHostname[strlen(LocalHostname)]; + + if ( (fp = popen("domainname", "r")) != 0 ) + { + int c; + + *pChr++ = '.'; + + while ((c = getc(fp)) != EOF) + { + if (! isspace(c)) + *pChr++ = (sal_Char)c; + } + + *pChr = '\0'; + + fclose(fp); + } + else + LocalHostname[0] = '\0'; + } +#endif /* OBSOLETE */ + + } + if (Addr) + osl_destroyHostAddr(Addr); + } + } + + if (strlen(LocalHostname) > 0) + { + strncpy(pBuffer, LocalHostname, nBufLen); + pBuffer[nBufLen - 1] = '\0'; + + return osl_Socket_Ok; + } + + return osl_Socket_Error; +} + +/*****************************************************************************/ +/* osl_resolveHostname */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_resolveHostname(rtl_uString *ustrHostname) +{ + oslSocketAddr Addr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName = rtl_string_getStr(strHostname); + } + + + Addr = osl_psz_resolveHostname(pszHostName); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + + return Addr; +} + + +oslSocketAddr SAL_CALL osl_psz_resolveHostname(const sal_Char* pszHostname) +{ + struct oslHostAddrImpl *pAddr = (oslHostAddr)osl_psz_createHostAddrByName(pszHostname); + + if (pAddr) + { + oslSocketAddr SockAddr = osl_copySocketAddr(pAddr->pSockAddr); + + osl_destroyHostAddr(pAddr); + + return (SockAddr); + } + + return ((oslSocketAddr)NULL); +} + +/*****************************************************************************/ +/* osl_getServicePort */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getServicePort(rtl_uString *ustrServicename, rtl_uString *ustrProtocol) +{ + sal_Int32 nPort; + rtl_String* strServicename=0; + rtl_String* strProtocol=0; + sal_Char* pszServiceName=0; + sal_Char* pszProtocol=0; + + if ( ustrServicename != 0 ) + { + rtl_uString2String( &strServicename, + rtl_uString_getStr(ustrServicename), + rtl_uString_getLength(ustrServicename), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszServiceName = rtl_string_getStr(strServicename); + } + + if ( ustrProtocol != 0 ) + { + rtl_uString2String( &strProtocol, + rtl_uString_getStr(ustrProtocol), + rtl_uString_getLength(ustrProtocol), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszProtocol = rtl_string_getStr(strProtocol); + } + + nPort = osl_psz_getServicePort(pszServiceName,pszProtocol); + + if ( strServicename != 0 ) + { + rtl_string_release(strServicename); + } + + if ( strProtocol != 0 ) + { + rtl_string_release(strProtocol); + } + + + return nPort; +} + + +sal_Int32 SAL_CALL osl_psz_getServicePort(const sal_Char* pszServicename, + const sal_Char* pszProtocol) +{ + struct servent* ps; + + ps= getservbyname(pszServicename, pszProtocol); + + if (ps != 0) + return ntohs(ps->s_port); + + return OSL_INVALID_PORT; +} + +/*****************************************************************************/ +/* osl_destroySocketAddr */ +/*****************************************************************************/ +void SAL_CALL osl_destroySocketAddr(oslSocketAddr pAddr) +{ + __osl_destroySocketAddr( pAddr ); +} + +/*****************************************************************************/ +/* osl_getFamilyOfSocketAddr */ +/*****************************************************************************/ +oslAddrFamily SAL_CALL osl_getFamilyOfSocketAddr(oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return FAMILY_FROM_NATIVE(pAddr->m_sockaddr.sa_family); + else + return osl_Socket_FamilyInvalid; +} + +/*****************************************************************************/ +/* osl_getInetPortOfSocketAddr */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getInetPortOfSocketAddr(oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + if ( pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + return ntohs(pSystemInetAddr->sin_port); + } + return OSL_INVALID_PORT; +} + +/*****************************************************************************/ +/* osl_setInetPortOfSocketAddr */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setInetPortOfSocketAddr(oslSocketAddr pAddr, sal_Int32 Port) +{ + OSL_ASSERT(pAddr); + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + if ( pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + pSystemInetAddr->sin_port= htons((short)Port); + return sal_True; + } + } + + /* this is not a inet-addr => can't set port */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_getHostnameOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getHostnameOfSocketAddr(oslSocketAddr Addr, rtl_uString **ustrHostname) +{ + oslSocketResult Result; + sal_Char pszHostname[1024]; + + pszHostname[0] = '\0'; + + Result = osl_psz_getHostnameOfSocketAddr(Addr,pszHostname,sizeof(pszHostname)); + + rtl_uString_newFromAscii(ustrHostname,pszHostname); + + return Result; +} + + +oslSocketResult SAL_CALL osl_psz_getHostnameOfSocketAddr(oslSocketAddr pAddr, + sal_Char *pBuffer, sal_uInt32 BufferSize) +{ + oslHostAddr pHostAddr= (oslHostAddr )osl_createHostAddrByAddr(pAddr); + + if (pHostAddr) + { + strncpy(pBuffer, pHostAddr->pHostName, BufferSize); + + pBuffer[BufferSize - 1] = '\0'; + + osl_destroyHostAddr(pHostAddr); + + return osl_Socket_Ok; + } + + return osl_Socket_Error; +} + +/*****************************************************************************/ +/* osl_getDottedInetAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getDottedInetAddrOfSocketAddr(oslSocketAddr Addr, rtl_uString **ustrDottedInetAddr) +{ + oslSocketResult Result; + sal_Char pszDottedInetAddr[1024]; + + pszDottedInetAddr[0] = '\0'; + + Result = osl_psz_getDottedInetAddrOfSocketAddr(Addr,pszDottedInetAddr,sizeof(pszDottedInetAddr)); + + rtl_uString_newFromAscii(ustrDottedInetAddr,pszDottedInetAddr); + + return Result; + +} + +oslSocketResult SAL_CALL osl_psz_getDottedInetAddrOfSocketAddr(oslSocketAddr pAddr, + sal_Char *pBuffer, sal_uInt32 BufferSize) +{ + OSL_ASSERT(pAddr); + + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr = ( struct sockaddr_in * ) &(pAddr->m_sockaddr); + + if (pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + strncpy(pBuffer, inet_ntoa(pSystemInetAddr->sin_addr), BufferSize); + pBuffer[BufferSize - 1] = '\0'; + + return osl_Socket_Ok; + } + } + + return osl_Socket_Error; +} + +#if 0 /* OBSOLETE */ +/*****************************************************************************/ +/* osl_getIpxNetNumber */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getIpxNetNumber(oslSocketAddr Addr, + oslSocketIpxNetNumber NetNumber) + +{ + struct sockaddr_ipx* pAddr; + + pAddr= (struct sockaddr_ipx*)Addr; + + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + { + memcpy(NetNumber, pAddr->sa_netnum, sizeof(NetNumber)); + + return osl_Socket_Ok; + } + else + return osl_Socket_Error; +} + + +/*****************************************************************************/ +/* osl_getIpxNodeNumber */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getIpxNodeNumber(oslSocketAddr Addr, + oslSocketIpxNodeNumber NodeNumber) + +{ + struct sockaddr_ipx* pAddr; + + pAddr= (struct sockaddr_ipx*)Addr; + + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + { + memcpy(NodeNumber, pAddr->sa_nodenum, sizeof(NodeNumber)); + + return osl_Socket_Ok; + } + else + return osl_Socket_Error; +} + + +/*****************************************************************************/ +/* osl_getIpxSocketNumber */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getIpxSocketNumber(oslSocketAddr Addr) +{ + struct sockaddr_ipx* pAddr= (struct sockaddr_ipx*)Addr; + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + return pAddr->sa_socket; + else + return OSL_INVALID_IPX_SOCKET_NO; +} + +#endif /* OBSOLETE */ + +/*****************************************************************************/ +/* osl_createSocket */ +/*****************************************************************************/ +oslSocket SAL_CALL osl_createSocket(oslAddrFamily Family, + oslSocketType Type, + oslProtocol Protocol) +{ + int Flags; + oslSocket pSocket; + + /* alloc memory */ + pSocket= __osl_createSocketImpl(OSL_INVALID_SOCKET); + + /* create socket */ + pSocket->m_Socket= socket(FAMILY_TO_NATIVE(Family), + TYPE_TO_NATIVE(Type), + PROTOCOL_TO_NATIVE(Protocol)); + + /* creation failed => free memory */ + if(pSocket->m_Socket == OSL_INVALID_SOCKET) + { + OSL_TRACE("osl_createSocket failed. Errno: %d; %s\n", + errno, + strerror(errno)); + + __osl_destroySocketImpl((pSocket)); + pSocket= 0; + } + else + { + /* set close-on-exec flag */ + if ((Flags = fcntl(pSocket->m_Socket, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + if (fcntl(pSocket->m_Socket, F_SETFD, Flags) == -1) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_createSocket failed changing socket flags. Errno: %d; %s\n", + errno, + strerror(errno)); + } + } + else + { + pSocket->m_nLastError=errno; + } + + + pSocket->m_CloseCallback = NULL; + pSocket->m_CallbackArg = NULL; + } + + return pSocket; +} + +void SAL_CALL osl_acquireSocket(oslSocket pSocket) +{ + osl_incrementInterlockedCount( &(pSocket->m_nRefCount ) ); +} + +void SAL_CALL osl_releaseSocket( oslSocket pSocket ) +{ + if( pSocket && 0 == osl_decrementInterlockedCount( &(pSocket->m_nRefCount) ) ) + { +#if defined(LINUX) + if ( pSocket->m_bIsAccepting == sal_True ) + { + OSL_ENSURE(0, "osl_destroySocket : attempt to destroy socket while accepting\n"); + return; + } +#endif /* LINUX */ + osl_closeSocket( pSocket ); + __osl_destroySocketImpl( pSocket ); + } +} + + + +/*****************************************************************************/ +/* osl_closeSocket */ +/*****************************************************************************/ +void SAL_CALL osl_closeSocket(oslSocket pSocket) +{ + int nRet; + int nFD; + + /* socket already invalid */ + if(pSocket==0) + return; + + pSocket->m_nLastError=0; + nFD = pSocket->m_Socket; + + pSocket->m_Socket = OSL_INVALID_SOCKET; + +#if defined(LINUX) + pSocket->m_bIsInShutdown = sal_True; + + if ( pSocket->m_bIsAccepting == sal_True ) + { + int nConnFD; + struct sockaddr aSockAddr; + socklen_t nSockLen = sizeof(aSockAddr); + + nRet = getsockname(nFD, &aSockAddr, &nSockLen); +#if OSL_DEBUG_LEVEL > 1 + if ( nRet < 0 ) + { + perror("getsockname"); + } +#endif /* OSL_DEBUG_LEVEL */ + + if ( aSockAddr.sa_family == AF_INET ) + { + struct sockaddr_in* pSockAddrIn = (struct sockaddr_in*) &aSockAddr; + + if ( pSockAddrIn->sin_addr.s_addr == htonl(INADDR_ANY) ) + { + pSockAddrIn->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + + nConnFD = socket(AF_INET, SOCK_STREAM, 0); +#if OSL_DEBUG_LEVEL > 1 + if ( nConnFD < 0 ) + { + perror("socket"); + } +#endif /* OSL_DEBUG_LEVEL */ + + nRet = connect(nConnFD, &aSockAddr, sizeof(aSockAddr)); +#if OSL_DEBUG_LEVEL > 1 + if ( nRet < 0 ) + { + perror("connect"); + } +#endif /* OSL_DEBUG_LEVEL */ + close(nConnFD); + } + } +#endif /* LINUX */ + + /* registrierten Callback ausfuehren */ + if (pSocket->m_CloseCallback != NULL) + { + pSocket->m_CloseCallback(pSocket->m_CallbackArg); + } + + nRet=close(nFD); + if ( nRet != 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("closeSocket close error '%s'\n",strerror(errno)); + } + + pSocket->m_Socket = OSL_INVALID_SOCKET; +} + +/*****************************************************************************/ +/* osl_getLocalAddrOfSocket */ +/* Note that I rely on the fact that oslSocketAddr and struct sockaddr */ +/* are the same! I don't like it very much but see no other easy way to conceal */ +/* the struct sockaddr from the eyes of the user. */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getLocalAddrOfSocket(oslSocket pSocket) +{ +#if defined(LINUX) || defined(FREEBSD) + socklen_t AddrLen; +#else + /* mfe: Solaris 'cc +w' means Addrlen should be signed! */ + /* it's really defined as 'int*' in /usr/include/sys/socket.h! */ + /* the man page says it expects a 'size_t' */ + int AddrLen; +#endif + struct sockaddr Addr; + oslSocketAddr pAddr; + + if (pSocket == NULL) /* ENOTSOCK */ + return ((oslSocketAddr)NULL); + + AddrLen= sizeof(struct sockaddr); + + if (getsockname(pSocket->m_Socket, &Addr, PTR_SIZE_T(AddrLen)) == OSL_SOCKET_ERROR) + return ((oslSocketAddr)NULL); + + pAddr = __osl_createSocketAddrFromSystem( &Addr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_getPeerAddrOfSocket */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getPeerAddrOfSocket(oslSocket pSocket) +{ + sal_uInt32 AddrLen; + struct sockaddr Addr; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return 0; + } + + pSocket->m_nLastError=0; + AddrLen= sizeof(struct sockaddr); + + if(getpeername(pSocket->m_Socket, &Addr, (int*)PTR_SIZE_T(AddrLen)) == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return 0; + } + return __osl_createSocketAddrFromSystem( &Addr ); +} + +/*****************************************************************************/ +/* osl_bindAddrToSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_bindAddrToSocket(oslSocket pSocket, + oslSocketAddr pAddr) +{ + int nRet; + + OSL_ASSERT(pSocket && pAddr ); + if ( pSocket == 0 || pAddr == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = bind(pSocket->m_Socket, &(pAddr->m_sockaddr), sizeof(struct sockaddr)); + + if ( nRet == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + + +/*****************************************************************************/ +/* osl_listenOnSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_listenOnSocket(oslSocket pSocket, + sal_Int32 MaxPendingConnections) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = listen(pSocket->m_Socket, + MaxPendingConnections == -1 ? + SOMAXCONN : + MaxPendingConnections); + if ( nRet == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + + +/*****************************************************************************/ +/* osl_connectSocketTo */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_connectSocketTo(oslSocket pSocket, + oslSocketAddr pAddr, + const TimeValue* pTimeout) +{ + fd_set WriteSet; + fd_set ExcptSet; + int ReadyHandles; + struct timeval tv; + oslSocketResult Result= osl_Socket_Ok; + + OSL_PRECOND(pSocket, "osl_connectSocketTo(): need a valid socket!\n"); + + if ( pSocket == 0 ) + { + return osl_Socket_Error; + } + + pSocket->m_nLastError=0; + + if (osl_isNonBlockingMode(pSocket)) + { + if (connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) != OSL_SOCKET_ERROR) + return osl_Socket_Ok; + else + if (errno == EWOULDBLOCK || errno == EINPROGRESS) + { + pSocket->m_nLastError=EINPROGRESS; + return osl_Socket_InProgress; + } + + + pSocket->m_nLastError=errno; + OSL_TRACE("can't connect : '%s'",strerror(errno)); + return osl_Socket_Error; + } + + /* set socket temporarily to non-blocking */ + OSL_VERIFY(osl_enableNonBlockingMode(pSocket, sal_True)); + + /* initiate connect */ + if(connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) != OSL_SOCKET_ERROR) + { + /* immediate connection */ + osl_enableNonBlockingMode(pSocket, sal_False); + + return osl_Socket_Ok; + } + else + { + /* really an error or just delayed? */ + if (errno != EINPROGRESS) + { + pSocket->m_nLastError=errno; + OSL_TRACE( + "osl_connectSocketTo(): connect failed: errno: %d (%s)\n", + errno, strerror(errno)); + + osl_enableNonBlockingMode(pSocket, sal_False); + return osl_Socket_Error; + } + } + + + /* prepare select set for socket */ + FD_ZERO(&WriteSet); + FD_ZERO(&ExcptSet); + FD_SET(pSocket->m_Socket, &WriteSet); + FD_SET(pSocket->m_Socket, &ExcptSet); + + /* prepare timeout */ + if (pTimeout) + { + /* divide milliseconds into seconds and microseconds */ + tv.tv_sec= pTimeout->Seconds; + tv.tv_usec= pTimeout->Nanosec / 1000L; + } + + /* select */ + ReadyHandles= select(pSocket->m_Socket+1, + 0, + PTR_FD_SET(WriteSet), + PTR_FD_SET(ExcptSet), + (pTimeout) ? &tv : 0); + + if (ReadyHandles > 0) /* connected */ + { + if ( FD_ISSET(pSocket->m_Socket, &WriteSet ) ) + { + int nErrorCode = 0; +#ifdef SOLARIS +/* mfe: Solaris 'cc +w' means 5th argument should be a 'int*'! + it's really defined as 'int*' in /usr/include/sys/socket.h! + the man page says it expects a 'size_t*' +*/ + int nErrorSize = sizeof( nErrorCode ); +#else + size_t nErrorSize = sizeof( nErrorCode ); +#endif + + int nSockOpt; + + nSockOpt = getsockopt ( pSocket->m_Socket, SOL_SOCKET, SO_ERROR, +#ifdef SOLARIS +/* mfe: Solaris 'cc +w' means 4th argument should be a 'char*'! + it's really defined as 'char*' in /usr/include/sys/socket.h! + the man page says it expects a 'void*' +*/ + (char*) +#endif + &nErrorCode, (int*)&nErrorSize ); + if ( (nSockOpt == 0) && (nErrorCode == 0)) + Result = osl_Socket_Ok; + else + Result = osl_Socket_Error; + } + else + { + Result= osl_Socket_Error; + } + } + else if (ReadyHandles < 0) /* error */ + { + if (errno == EBADF) /* most probably interrupted by close() */ + { + /* do not access pSockImpl because it is about to be or */ + /* already destroyed */ + return osl_Socket_Interrupted; + } + else + { + pSocket->m_nLastError=errno; + Result= osl_Socket_Error; + } + } + else /* timeout */ + { + pSocket->m_nLastError=errno; + Result= osl_Socket_TimedOut; + } + + osl_enableNonBlockingMode(pSocket, sal_False); + + return Result; +} + + +/*****************************************************************************/ +/* osl_acceptConnectionOnSocket */ +/*****************************************************************************/ +oslSocket SAL_CALL osl_acceptConnectionOnSocket(oslSocket pSocket, + oslSocketAddr* ppAddr) +{ + struct sockaddr Addr; + int Connection, Flags; + sal_uInt32 AddrLen = sizeof(struct sockaddr); + oslSocket pConnectionSockImpl; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return 0; + } + + pSocket->m_nLastError=0; +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_True; +#endif /* LINUX */ + + if( ppAddr && *ppAddr ) + { + osl_destroySocketAddr( *ppAddr ); + *ppAddr = 0; + } + + /* prevent Linux EINTR behaviour */ + do + { + Connection = accept(pSocket->m_Socket, &Addr, (int*)PTR_SIZE_T(AddrLen)); + } while (Connection == -1 && errno == EINTR); + + + /* accept failed? */ + if( Connection == OSL_SOCKET_ERROR ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_acceptConnectionOnSocket : accept error '%s'\n",strerror(errno)); + +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_False; +#endif /* LINUX */ + return 0; + } + + OSL_ASSERT(AddrLen == sizeof(struct sockaddr)); + + +#if defined(LINUX) + if ( pSocket->m_bIsInShutdown == sal_True ) + { + close(Connection); + OSL_TRACE("osl_acceptConnectionOnSocket : close while accept\n"); + return 0; + } +#endif /* LINUX */ + + + if(ppAddr) + { + *ppAddr= __osl_createSocketAddrFromSystem(&Addr); + } + + /* alloc memory */ + pConnectionSockImpl= __osl_createSocketImpl(OSL_INVALID_SOCKET); + + /* set close-on-exec flag */ + if ((Flags = fcntl(Connection, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + if (fcntl(Connection, F_SETFD, Flags) == -1) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_acceptConnectionOnSocket failed changing socket flags. Errno: %d (%s)\n", + errno, + strerror(errno)); + } + + } + + pConnectionSockImpl->m_Socket = Connection; + pConnectionSockImpl->m_nLastError = 0; + pConnectionSockImpl->m_CloseCallback = NULL; + pConnectionSockImpl->m_CallbackArg = NULL; +#if defined(LINUX) + pConnectionSockImpl->m_bIsAccepting = sal_False; + + pSocket->m_bIsAccepting = sal_False; +#endif /* LINUX */ + return pConnectionSockImpl; +} + +/*****************************************************************************/ +/* osl_receiveSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receiveSocket(oslSocket pSocket, + void* pBuffer, + sal_uInt32 BytesToRead, + oslSocketMsgFlag Flag) +{ + int nRead; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_receiveSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + do + { + nRead = recv(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToRead, + MSG_FLAG_TO_NATIVE(Flag)); + } while ( nRead < 0 && errno == EINTR ); + + if ( nRead < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,strerror(errno)); + } + else if ( nRead == 0 ) + { + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,"EOL"); + } + + return nRead; +} + + +/*****************************************************************************/ +/* osl_receiveFromSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receiveFromSocket(oslSocket pSocket, + oslSocketAddr pSenderAddr, + void* pBuffer, + sal_uInt32 BufferSize, + oslSocketMsgFlag Flag) +{ + int nRead; + struct sockaddr *pSystemSockAddr = 0; + int AddrLen = 0; + if( pSenderAddr ) + { + AddrLen = sizeof( struct sockaddr ); + pSystemSockAddr = &(pSenderAddr->m_sockaddr); + } + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_receiveFromSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + nRead = recvfrom(pSocket->m_Socket, + (sal_Char*)pBuffer, + BufferSize, + MSG_FLAG_TO_NATIVE(Flag), + pSystemSockAddr, + PTR_SIZE_T(AddrLen)); + + if ( nRead < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_receiveFromSocket failed : %i '%s'",nRead,strerror(errno)); + } + else if ( nRead == 0 ) + { + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,"EOL"); + } + + return nRead; +} + + +/*****************************************************************************/ +/* osl_sendSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendSocket(oslSocket pSocket, + const void* pBuffer, + sal_uInt32 BytesToSend, + oslSocketMsgFlag Flag) +{ + int nWritten; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_sendSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + do + { + nWritten = send(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, + MSG_FLAG_TO_NATIVE(Flag)); + } while ( nWritten < 0 && errno == EINTR ); + + + if ( nWritten < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_sendSocket failed : %i '%s'",nWritten,strerror(errno)); + } + else if ( nWritten == 0 ) + { + OSL_TRACE("osl_sendSocket failed : %i '%s'",nWritten,"EOL"); + } + + return nWritten; +} + +/*****************************************************************************/ +/* osl_sendToSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendToSocket(oslSocket pSocket, + oslSocketAddr ReceiverAddr, + const void* pBuffer, + sal_uInt32 BytesToSend, + oslSocketMsgFlag Flag) +{ + int nWritten; + + struct sockaddr *pSystemSockAddr = 0; + int AddrLen = 0; + if( ReceiverAddr ) + { + pSystemSockAddr = &(ReceiverAddr->m_sockaddr); + AddrLen = sizeof( struct sockaddr ); + } + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_sendToSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + /* ReceiverAddr might be 0 when used on a connected socket. */ + /* Then sendto should behave like send. */ + + nWritten = sendto(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, + MSG_FLAG_TO_NATIVE(Flag), + pSystemSockAddr, + AddrLen); + + if ( nWritten < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_sendToSocket failed : %i '%s'",nWritten,strerror(errno)); + } + else if ( nWritten == 0 ) + { + OSL_TRACE("osl_sendToSocket failed : %i '%s'",nWritten,"EOL"); + } + + return nWritten; +} + +/*****************************************************************************/ +/* osl_readSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_readSocket ( + oslSocket pSocket, void *pBuffer, sal_Int32 n ) +{ + sal_uInt8 * Ptr = (sal_uInt8 *)pBuffer; + sal_uInt32 BytesRead= 0; + sal_uInt32 BytesToRead= n; + + OSL_ASSERT( pSocket); + + /* loop until all desired bytes were read or an error occured */ + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receiveSocket(pSocket, + Ptr, + BytesToRead, + osl_Socket_MsgNormal); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToRead -= RetVal; + BytesRead += RetVal; + Ptr += RetVal; + } + + return BytesRead; +} + +/*****************************************************************************/ +/* osl_writeSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_writeSocket( + oslSocket pSocket, const void *pBuffer, sal_Int32 n ) +{ + /* loop until all desired bytes were send or an error occured */ + sal_uInt32 BytesSend= 0; + sal_uInt32 BytesToSend= n; + sal_uInt8 *Ptr = ( sal_uInt8 * )pBuffer; + + OSL_ASSERT( pSocket ); + + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendSocket( pSocket,Ptr,BytesToSend,osl_Socket_MsgNormal); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToSend -= RetVal; + BytesSend += RetVal; + Ptr += RetVal; + + } + return BytesSend; +} + +/*****************************************************************************/ +/* __osl_socket_poll */ +/*****************************************************************************/ + +#ifdef HAVE_POLL_H /* poll() */ + +sal_Bool __osl_socket_poll ( + oslSocket pSocket, + const TimeValue* pTimeout, + short nEvent) +{ + struct pollfd fds; + int timeout; + int result; + + OSL_ASSERT(pSocket); + pSocket->m_nLastError = 0; + + fds.fd = pSocket->m_Socket; + fds.events = nEvent; + fds.revents = 0; + + timeout = -1; + if (pTimeout) + { + /* Convert to [ms] */ + timeout = pTimeout->Seconds * 1000; + timeout += pTimeout->Nanosec / (1000 * 1000); + } + + result = poll (&fds, 1, timeout); + if (result < 0) + { + pSocket->m_nLastError = errno; + OSL_TRACE("__osl_socket_poll(): poll error: %d (%s)", + errno, strerror(errno)); + return sal_False; + } + if (result == 0) + { + /* Timeout */ + return sal_False; + } + + return ((fds.revents & nEvent) == nEvent); +} + +#else /* select() */ + +sal_Bool __osl_socket_poll ( + oslSocket pSocket, + const TimeValue* pTimeout, + short nEvent) +{ + fd_set fds; + struct timeval tv; + int result; + + OSL_ASSERT(pSocket); + pSocket->m_nLastError = 0; + + FD_ZERO(&fds); + FD_SET(pSocket->m_Socket, &fds); + + if (pTimeout) + { + /* Convert to 'timeval' */ + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000; + } + + result = select ( + pSocket->m_Socket + 1, + (nEvent == POLLIN ) ? PTR_FD_SET(fds) : NULL, + (nEvent == POLLOUT) ? PTR_FD_SET(fds) : NULL, + (nEvent == POLLPRI) ? PTR_FD_SET(fds) : NULL, + (pTimeout) ? &tv : NULL); + + if (result < 0) + { + pSocket->m_nLastError = errno; + OSL_TRACE("__osl_socket_poll(): select error: %d (%s)", + errno, strerror(errno)); + return sal_False; + } + if (result == 0) + { + /* Timeout */ + return sal_False; + } + + return (FD_ISSET(pSocket->m_Socket, &fds) ? sal_True : sal_False); +} + +#endif /* HAVE_POLL_H */ + +/*****************************************************************************/ +/* osl_isReceiveReady */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isReceiveReady ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLIN); +} + +/*****************************************************************************/ +/* osl_isSendReady */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isSendReady ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLOUT); +} + +/*****************************************************************************/ +/* osl_isExceptionPending */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isExceptionPending ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLPRI); +} + +/*****************************************************************************/ +/* osl_shutdownSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_shutdownSocket(oslSocket pSocket, + oslSocketDirection Direction) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet=shutdown(pSocket->m_Socket, DIRECTION_TO_NATIVE(Direction)); + if (nRet != 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("shutdown error '%s'\n",strerror(errno)); + } + return (nRet==0); +} + + +/*****************************************************************************/ +/* osl_getSocketOption */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getSocketOption(oslSocket pSocket, + oslSocketOptionLevel Level, + oslSocketOption Option, + void* pBuffer, + sal_uInt32 BufferLen) +{ + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return -1; + } + + pSocket->m_nLastError=0; + + if(getsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(Level), + OPTION_TO_NATIVE(Option), + (sal_Char*)pBuffer, + (int*)PTR_SIZE_T(BufferLen)) == -1) + { + pSocket->m_nLastError=errno; + return -1; + } + + return BufferLen; +} + +/*****************************************************************************/ +/* osl_setSocketOption */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setSocketOption(oslSocket pSocket, + oslSocketOptionLevel Level, + oslSocketOption Option, + void* pBuffer, + sal_uInt32 BufferLen) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = setsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(Level), + OPTION_TO_NATIVE(Option), + (sal_Char*)pBuffer, + BufferLen); + + if ( nRet < 0 ) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + +/*****************************************************************************/ +/* osl_enableNonBlockingMode */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_enableNonBlockingMode(oslSocket pSocket, + sal_Bool On) +{ + int flags; + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + flags = fcntl(pSocket->m_Socket, F_GETFL, 0); + + if (On) + flags |= O_NONBLOCK; + else + flags &= ~(O_NONBLOCK); + + nRet = fcntl(pSocket->m_Socket, F_SETFL, flags); + + if ( nRet < 0 ) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + +/*****************************************************************************/ +/* osl_isNonBlockingMode */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isNonBlockingMode(oslSocket pSocket) +{ + int flags; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + flags = fcntl(pSocket->m_Socket, F_GETFL, 0); + + if (flags == -1 || !(flags & O_NONBLOCK)) + return sal_False; + else + return sal_True; +} + +/*****************************************************************************/ +/* osl_getSocketType */ +/*****************************************************************************/ +oslSocketType SAL_CALL osl_getSocketType(oslSocket pSocket) +{ + int Type=0; + sal_uInt32 TypeSize= sizeof(Type); + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return osl_Socket_TypeInvalid; + } + + pSocket->m_nLastError=0; + + if(getsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(osl_Socket_LevelSocket), + OPTION_TO_NATIVE(osl_Socket_OptionType), + (sal_Char*)&Type, + (int*)PTR_SIZE_T(TypeSize)) == -1) + { + /* error */ + pSocket->m_nLastError=errno; + return osl_Socket_TypeInvalid; + } + + return TYPE_FROM_NATIVE(Type); + +} + +/*****************************************************************************/ +/* osl_getLastSocketErrorDescription */ +/*****************************************************************************/ +void SAL_CALL osl_getLastSocketErrorDescription(oslSocket Socket, rtl_uString **ustrError) +{ + sal_Char pszError[1024]; + + pszError[0] = '\0'; + + osl_psz_getLastSocketErrorDescription(Socket,pszError,sizeof(pszError)); + + rtl_uString_newFromAscii(ustrError,pszError); + + return; +} + + +void SAL_CALL osl_psz_getLastSocketErrorDescription(oslSocket pSocket, sal_Char* pBuffer, sal_uInt32 BufferSize) +{ + /* make shure pBuffer will be a zero-terminated string even when strncpy has to cut */ + pBuffer[BufferSize-1]= '\0'; + + if ( pSocket == 0 ) + { + strncpy(pBuffer, strerror(EINVAL), BufferSize-1); + return; + } + + strncpy(pBuffer, strerror(pSocket->m_nLastError), BufferSize-1); + return; +} + +/*****************************************************************************/ +/* osl_getLastSocketError */ +/*****************************************************************************/ +oslSocketError SAL_CALL osl_getLastSocketError(oslSocket pSocket) +{ + if ( pSocket == 0 ) + { + return ERROR_FROM_NATIVE(EINVAL); + } + + return ERROR_FROM_NATIVE(pSocket->m_nLastError); +} + +/*****************************************************************************/ +/* SocketSet */ +/*****************************************************************************/ +typedef struct _TSocketSetImpl +{ + int m_MaxHandle; /* for select(), the largest descriptor in the set */ + fd_set m_Set; /* the set of descriptors */ + +} TSocketSetImpl; + +/*****************************************************************************/ +/* osl_createSocketSet */ +/*****************************************************************************/ +oslSocketSet SAL_CALL osl_createSocketSet() +{ + TSocketSetImpl* pSet; + + pSet= (TSocketSetImpl*)malloc(sizeof(TSocketSetImpl)); + + OSL_ASSERT(pSet); + + if(pSet) + { + pSet->m_MaxHandle= 0; + FD_ZERO(&pSet->m_Set); + } + + return (oslSocketSet)pSet; +} + +/*****************************************************************************/ +/* osl_destroySocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_destroySocketSet(oslSocketSet Set) +{ + if(Set) + free(Set); +} + +/*****************************************************************************/ +/* osl_clearSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_clearSocketSet(oslSocketSet Set) +{ + TSocketSetImpl* pSet; + OSL_ASSERT(Set); + if ( Set == 0 ) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + pSet->m_MaxHandle= 0; + + FD_ZERO(&pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_addToSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_addToSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + + if ( Set == 0 || pSocket == 0) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + + /* correct max handle */ + if(pSocket->m_Socket > pSet->m_MaxHandle) + pSet->m_MaxHandle= pSocket->m_Socket; + FD_SET(pSocket->m_Socket, &pSet->m_Set); + +} + +/*****************************************************************************/ +/* osl_removeFromSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_removeFromSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + + if ( Set == 0 || pSocket == 0) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + + /* correct max handle */ + if(pSocket->m_Socket == pSet->m_MaxHandle) + { + /* not optimal, since the next used descriptor might be */ + /* much smaller than m_Socket-1, but it will do */ + pSet->m_MaxHandle--; + if(pSet->m_MaxHandle < 0) + { + pSet->m_MaxHandle= 0; /* avoid underflow */ + } + } + + FD_CLR(pSocket->m_Socket, &pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_isInSocketSet */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isInSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + if ( Set == 0 || pSocket == 0 ) + { + return sal_False; + } + + pSet= (TSocketSetImpl*)Set; + + return (FD_ISSET(pSocket->m_Socket, &pSet->m_Set) != 0); +} + +/*****************************************************************************/ +/* osl_demultiplexSocketEvents */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_demultiplexSocketEvents(oslSocketSet IncomingSet, + oslSocketSet OutgoingSet, + oslSocketSet OutOfBandSet, + const TimeValue* pTimeout) +{ + int MaxHandle= 0; + struct timeval tv; + TSocketSetImpl* pInSet; + TSocketSetImpl* pOutSet; + TSocketSetImpl* pOOBSet; + + if (pTimeout) + { + /* non-blocking call */ + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000L; + } + + /* map opaque data to impl-types */ + pInSet= (TSocketSetImpl*)IncomingSet; + pOutSet= (TSocketSetImpl*)OutgoingSet; + pOOBSet= (TSocketSetImpl*)OutOfBandSet; + + /* get max handle from all sets */ + if (pInSet) + MaxHandle= pInSet->m_MaxHandle; + + if (pOutSet && (pOutSet->m_MaxHandle > MaxHandle)) + MaxHandle= pOutSet->m_MaxHandle; + + if (pOOBSet && (pOOBSet->m_MaxHandle > MaxHandle)) + MaxHandle= pOOBSet->m_MaxHandle; + + return select(MaxHandle+1, + pInSet ? PTR_FD_SET(pInSet->m_Set) : 0, + pOutSet ? PTR_FD_SET(pOutSet->m_Set) : 0, + pOOBSet ? PTR_FD_SET(pOOBSet->m_Set) : 0, + pTimeout ? &tv : 0); +} + diff --git a/sal/osl/os2/sockimpl.h b/sal/osl/os2/sockimpl.h new file mode 100644 index 000000000000..38fc26bf0d22 --- /dev/null +++ b/sal/osl/os2/sockimpl.h @@ -0,0 +1,80 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_SOCKETIMPL_H_ +#define _OSL_SOCKETIMPL_H_ + +#include <osl/pipe.h> +#include <osl/socket.h> +#include <osl/interlck.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (*oslCloseCallback) (void*); + +struct oslSocketImpl { + int m_Socket; + int m_nLastError; + oslCloseCallback m_CloseCallback; + void* m_CallbackArg; + oslInterlockedCount m_nRefCount; +#if defined(LINUX) + sal_Bool m_bIsAccepting; + sal_Bool m_bIsInShutdown; +#endif +}; + +struct oslSocketAddrImpl +{ + sal_Int32 m_nRefCount; + struct sockaddr m_sockaddr; +}; + +/* +struct oslPipeImpl { + int m_Socket; + sal_Char m_Name[PATH_MAX + 1]; + oslInterlockedCount m_nRefCount; + sal_Bool m_bClosed; +#if defined(LINUX) + sal_Bool m_bIsAccepting; + sal_Bool m_bIsInShutdown; +#endif +}; +*/ + +oslSocket __osl_createSocketImpl(int Socket); +void __osl_destroySocketImpl(oslSocket pImpl); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/os2/system.h b/sal/osl/os2/system.h new file mode 100644 index 000000000000..ac7e410c5a34 --- /dev/null +++ b/sal/osl/os2/system.h @@ -0,0 +1,514 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __OSL_SYSTEM_H__ +#define __OSL_SYSTEM_H__ + +#define PTHREAD_NONE + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> + +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <signal.h> +#include <utime.h> + +#include <pwd.h> + +#include <netdb.h> + +#include <sys/stat.h> +#include <sys/wait.h> + +#include <sys/types.h> + +/* OS/2 API header */ +#define INCL_WINPROGRAMLIST +#define INCL_WINSHELLDATA +#define INCL_BASE +#define INCL_DOSSIGNALS +#define INCL_DOSSEMAPHORES +#define INCL_DOSMODULEMGR +#define INCL_DOSERRORS +#define INCL_DOSSESMGR +#define INCL_DOSPROCESS +#define INCL_DOSNMPIPES +#define INCL_DOSMISC +#include <os2.h> + +typedef ULONG HANDLE; +#define _MAX_ENV 2048 +#define _MAX_CMD 2048 + +#ifdef __cplusplus +extern "C" +#endif +int debug_printf(const char *f, ...); + +/* Make sockets of type AF_UNIX use underlying FS rights */ +#ifdef SOLARIS +# define _XOPEN_SOURCE 500 +# include <sys/socket.h> +# undef _XOPEN_SOURCE +#else +# include <sys/socket.h> +#endif + +#include <netinet/in.h> +#include <arpa/inet.h> + +#define max(a, b) ((a) < (b) ? (b) : (a)) +#define min(a, b) ((a) > (b) ? (b) : (a)) +#ifndef abs +#define abs(x) ((x) >= 0 ? (x) : -(x)) +#endif + +#ifdef SYSV +# include <sys/utsname.h> +#endif + +#ifdef LINUX +# ifndef __USE_GNU +# define __USE_GNU +# endif + +#if GLIBC >= 2 +# include <shadow.h> +# if ! (defined(SPARC) || defined(X86_64)) +# include <asm/sigcontext.h> +# endif +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <sys/uio.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <dlfcn.h> +# include <endian.h> +# include <sys/time.h> +# include <semaphore.h> +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif __BYTE_ORDER == __BIG_ENDIAN +# define _BIG_ENDIAN +# elif __BYTE_ORDER == __PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define PTR_SIZE_T(s) ((size_t *)&(s)) +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_PRIORITY +# define PTHREAD_SIGACTION pthread_sigaction +#else +# include <shadow.h> +# include <asm/sigcontext.h> +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <linux/net.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <linux/elfcore.h> +# include <dlfcn.h> +# include <endian.h> +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif __BYTE_ORDER == __BIG_ENDIAN +# define _BIG_ENDIAN +# elif __BYTE_ORDER == __PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_RTL +# define NO_PTHREAD_PRIORITY +# define PTHREAD_SIGACTION pthread_sigaction +#endif +#endif + +#ifdef NETBSD +# define ETIME ETIMEDOUT +# define _POSIX_THREAD_SYSCALL_SOFT 1 +# include <pthread.h> +# include <netdb.h> +# include <sys/sem.h> +# include <sys/exec.h> +# include <sys/filio.h> +# include <sys/ioctl.h> +# include <sys/time.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <dlfcn.h> +# include <machine/endian.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN_OO +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN_OO +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN_OO +# endif +# define PTR_SIZE_T(s) ((size_t *)&(s)) +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_PRIORITY +# define NO_PTHREAD_SEMAPHORES +# define NO_PTHREAD_RTL +# define PTHREAD_SIGACTION pthread_sigaction +#endif + +#ifdef FREEBSD +# define ETIME ETIMEDOUT +# include <pthread.h> +# include <sys/sem.h> +# include <semaphore.h> +# include <dlfcn.h> +# include <sys/filio.h> +# include <sys/ioctl.h> +# include <sys/param.h> +# include <sys/time.h> +# include <sys/uio.h> +# include <sys/exec.h> +# include <vm/vm.h> +# include <vm/vm_param.h> +# include <vm/pmap.h> +# include <vm/swap_pager.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# define IORESOURCE_TRANSFER_BSD +# include <machine/endian.h> +#if __FreeBSD_version < 500000 +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +#endif +# define NO_PTHREAD_RTL +#endif + +#ifdef SCO +# define AF_IPX -1 +# include <strings.h> +# include <pthread.h> +# include <shadow.h> +# include <netdb.h> +# include <sys/un.h> +# include <sys/netinet/tcp.h> +# include <sys/types.h> +# include <sys/byteorder.h> +# include <dlfcn.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define sched_yield() pthread_yield() +# define pthread_testcancel() +# define NO_PTHREAD_RTL +# define NO_PTHREAD_PRIORITY +extern int pthread_cancel(pthread_t); +extern unsigned int nanosleep(unsigned int); +# define SLEEP_TIMESPEC(timespec) (timespec .tv_sec > 0) ? sleep(timespec .tv_sec), nanosleep(timespec .tv_nsec) : nanosleep(timespec .tv_nsec) +# define PATH_MAX _POSIX_PATH_MAX +# define S_ISSOCK S_ISFIFO +# define PTHREAD_SIGACTION pthread_sigaction +# define STAT_PARENT stat +#endif + +#ifdef AIX +# define AF_IPX -1 +# include <strings.h> +# include <pthread.h> +# include <sys/time.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <sys/machine.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define sched_yield() pthread_yield() +# define SLEEP_TIMESPEC(timespec) nsleep(×pec, 0) +# define LIBPATH "LIBPATH" +# define PTR_SIZE_T(s) ((size_t *)&(s)) +# define NO_PTHREAD_SEMAPHORES +# define NO_DL_FUNCTIONS +#endif + +#ifdef HPUX +# define AF_IPX -1 +# undef howmany +# undef MAXINT +# include <pthread.h> +# include <sys/un.h> +# include <sys/sched.h> +# include <sys/xti.h> +# include <sys/pstat.h> +# include <shadow.h> +# include <crypt.h> +# include <machine/param.h> +# define LIBPATH "SHLIB_PATH" +# define PTR_SIZE_T(s) ((int *)&(s)) +# define PTR_FD_SET(s) ((int *)&(s)) +# define PTHREAD_VALUE(t) ((t).field2) +# define PTHREAD_NONE_INIT { 0, -1 } +# define PTHREAD_ATTR_DEFAULT pthread_attr_default +# define PTHREAD_MUTEXATTR_DEFAULT pthread_mutexattr_default +# define PTHREAD_CONDATTR_DEFAULT pthread_condattr_default +# define pthread_detach(t) pthread_detach(&(t)) +# define NO_PTHREAD_PRIORITY +# define NO_PTHREAD_SEMAPHORES +# define NO_DL_FUNCTIONS +# undef sigaction +# define PTHREAD_SIGACTION cma_sigaction +#endif + +#ifdef SOLARIS +# include <shadow.h> +# include <sys/procfs.h> +# include <sys/un.h> +# include <stropts.h> +# include <pthread.h> +# include <semaphore.h> +# include <netinet/tcp.h> +# include <sys/filio.h> +# include <dlfcn.h> +# include <sys/isa_defs.h> +# define IORESOURCE_TRANSFER_SYSV +# define IOCHANNEL_TRANSFER_BSD +# define LIBPATH "LD_LIBRARY_PATH" +# define PTR_SIZE_T(s) ((int *)&(s)) +#endif + +#ifdef MACOSX +# define ETIME ETIMEDOUT +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <sys/uio.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <machine/endian.h> +# include <sys/time.h> +# include <sys/semaphore.h> +/* fixme are premac and postmac still needed here? */ +# include <premac.h> +# include <mach-o/dyld.h> +# include <postmac.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define IOCHANNEL_TRANSFER_BSD_RENO +# define NO_PTHREAD_RTL +/* for NSGetArgc/Argv/Environ */ +# include <crt_externs.h> +char *macxp_tempnam( const char *tmpdir, const char *prefix ); +#endif + +#ifdef OS2 +# include <netinet/tcp.h> +#endif + +#if !defined(_WIN32) && !defined(_WIN16) && !defined(OS2) && \ + !defined(LINUX) && !defined(NETBSD) && !defined(FREEBSD) && !defined(SCO) && \ + !defined(AIX) && !defined(HPUX) && \ + !defined(SOLARIS) && !defined(MAC) && \ + !defined(MACOSX) +# error "Target plattform not specified !" +#endif + +#if defined(NETBSD) +#if defined _LITTLE_ENDIAN_OO +# define _OSL_BIGENDIAN +#elif defined _BIG_ENDIAN_OO +# define _OSL_LITENDIAN +#else +# error undetermined endianess +#endif +#else +#if defined _LITTLE_ENDIAN +# define _OSL_BIGENDIAN +#elif defined _BIG_ENDIAN +# define _OSL_LITENDIAN +#else +# error undetermined endianess +#endif +#endif + +#ifndef PTR_SIZE_T +# define PTR_SIZE_T(s) (&(s)) +#endif + +#ifndef PTR_FD_SET +# define PTR_FD_SET(s) (&(s)) +#endif + +#ifndef NORMALIZE_TIMESPEC +# define NORMALIZE_TIMESPEC(timespec) \ + timespec . tv_sec += timespec . tv_nsec / 1000000000; \ + timespec . tv_nsec %= 1000000000; +#endif + +#ifndef SET_TIMESPEC +# define SET_TIMESPEC(timespec, sec, nsec) \ + timespec . tv_sec = (sec); \ + timespec . tv_nsec = (nsec); \ + NORMALIZE_TIMESPEC(timespec); +#endif + +#ifndef SLEEP_TIMESPEC +# define SLEEP_TIMESPEC(timespec) nanosleep(×pec, 0) +#endif + +#ifndef INIT_GROUPS +# define INIT_GROUPS(name, gid) ((setgid((gid)) == 0) && (initgroups((name), (gid)) == 0)) +#endif + +#ifndef PTHREAD_VALUE +# define PTHREAD_VALUE(t) (t) +#endif +#ifndef PTHREAD_NONE +extern pthread_t _pthread_none_; +# define PTHREAD_NONE _pthread_none_ +# ifndef PTHREAD_NONE_INIT +# define PTHREAD_NONE_INIT ((pthread_t)-1) +# endif +#endif + +#ifndef PTHREAD_ATTR_DEFAULT +# define PTHREAD_ATTR_DEFAULT NULL +#endif +#ifndef PTHREAD_MUTEXATTR_DEFAULT +# define PTHREAD_MUTEXATTR_DEFAULT NULL +#endif +#ifndef PTHREAD_CONDATTR_DEFAULT +# define PTHREAD_CONDATTR_DEFAULT NULL +#endif + +#ifndef PTHREAD_SIGACTION +# define PTHREAD_SIGACTION sigaction +#endif + +#ifndef STAT_PARENT +# define STAT_PARENT lstat +#endif + +/* socket options which might not be defined on all unx flavors */ +#ifndef SO_ACCEPTCONN +# define SO_ACCEPTCONN 0 +#endif +#ifndef SO_SNDLOWAT +# define SO_SNDLOWAT 0 +#endif +#ifndef SO_RCVLOWAT +# define SO_RCVLOWAT 0 +#endif +#ifndef SO_SNDTIMEO +# define SO_SNDTIMEO 0 +#endif +#ifndef SO_RCVTIMEO +# define SO_RCVTIMEO 0 +#endif +#ifndef SO_USELOOPBACK +# define SO_USELOOPBACK 0 +#endif +#ifndef MSG_MAXIOVLEN +# define MSG_MAXIOVLEN 0 +#endif + +/* BEGIN HACK */ +/* dummy define and declarations for IPX should be replaced by */ +/* original ipx headers when these are available for this platform */ + +#ifndef SA_FAMILY_DECL +# define SA_FAMILY_DECL short sa_family +#endif + +typedef struct sockaddr_ipx { + SA_FAMILY_DECL; + char sa_netnum[4]; + char sa_nodenum[6]; + unsigned short sa_socket; +} SOCKADDR_IPX; + +#define NSPROTO_IPX 1000 +#define NSPROTO_SPX 1256 +#define NSPROTO_SPXII 1257 + +/* END HACK */ + +#ifdef NO_PTHREAD_SEMAPHORES + +typedef struct +{ + pthread_mutex_t mutex; + pthread_cond_t increased; + int value; +} sem_t; +extern int sem_init(sem_t* sem, int pshared, unsigned int value); +extern int sem_destroy(sem_t* sem); +extern int sem_wait(sem_t* sem); +extern int sem_trywait(sem_t* sem); +extern int sem_post(sem_t* sem); + +#endif + +#ifdef NO_PTHREAD_RTL +#if !defined FREEBSD || (__FreeBSD_version < 500112) +struct passwd *getpwent_r(struct passwd *pwd, char *buffer, int buflen); +extern struct spwd *getspnam_r(const char *name, struct spwd *result, + char *buffer, int buflen); + +struct tm *localtime_r(const time_t *timep, struct tm *buffer); +struct tm *gmtime_r(const time_t *timep, struct tm *buffer); +#endif /* !defined FREEBSD || (__FreeBSD_version < 500112) */ +struct hostent *gethostbyname_r(const char *name, struct hostent *result, + char *buffer, int buflen, int *h_errnop); +#endif + +#endif /* __OSL_SYSTEM_H__ */ + diff --git a/sal/osl/os2/tempfile.c b/sal/osl/os2/tempfile.c new file mode 100644 index 000000000000..672995563c88 --- /dev/null +++ b/sal/osl/os2/tempfile.c @@ -0,0 +1,359 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/*****************************************************************/ +/* Includes */ +/*****************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "system.h" +#include <osl/file.h> +#include <osl/thread.h> +#include <rtl/ustrbuf.h> +#include <osl/diagnose.h> + +#ifndef _FILE_URL_H_ +#include "file_url.h" +#endif + +/*****************************************************************/ +/* osl_getTempFirURL */ +/*****************************************************************/ + +oslFileError SAL_CALL osl_getTempDirURL( rtl_uString** pustrTempDir ) +{ + const char *pValue = getenv( "TEMP" ); + + if ( !pValue ) + { + pValue = getenv( "TMP" ); +#if defined(SOLARIS) || defined (LINUX) || defined (FREEBSD) || defined (MACOSX) + if ( !pValue ) + pValue = P_tmpdir; +#endif + } + + if ( pValue ) + { + oslFileError error; + rtl_uString *ustrTempPath = NULL; + + rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(ustrTempPath != NULL); + error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir ); + rtl_uString_release( ustrTempPath ); + + return error; + } + else + return osl_File_E_NOENT; +} + +/****************************************************************** + * Generates a random unique file name. We're using the scheme + * from the standard c-lib function mkstemp to generate a more + * or less random unique file name + * + * @param rand_name + * receives the random name + ******************************************************************/ + +static const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; +static const int COUNT_OF_LETTERS = sizeof(LETTERS)/sizeof(LETTERS[0]) - 1; + +#define RAND_NAME_LENGTH 6 + +static void osl_gen_random_name_impl_(rtl_uString** rand_name) +{ + static uint64_t value; + + char buffer[RAND_NAME_LENGTH]; + struct timeval tv; + uint64_t v; + int i; + + gettimeofday(&tv, NULL); + + value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid(); + + v = value; + + for (i = 0; i < RAND_NAME_LENGTH; i++) + { + buffer[i] = LETTERS[v % COUNT_OF_LETTERS]; + v /= COUNT_OF_LETTERS; + } + + rtl_string2UString( + rand_name, + buffer, + RAND_NAME_LENGTH, + RTL_TEXTENCODING_ASCII_US, + OSTRING_TO_OUSTRING_CVTFLAGS); + OSL_ASSERT(*rand_name != NULL); +} + +/***************************************************************** + * Helper function + * Either use the directory provided or the result of + * osl_getTempDirUrl and return it as system path and file url + ****************************************************************/ + +static oslFileError osl_setup_base_directory_impl_( + rtl_uString* pustrDirectoryURL, + rtl_uString** ppustr_base_dir) +{ + rtl_uString* dir_url = 0; + rtl_uString* dir = 0; + oslFileError error = osl_File_E_None; + + if (pustrDirectoryURL) + rtl_uString_assign(&dir_url, pustrDirectoryURL); + else + error = osl_getTempDirURL(&dir_url); + + if (osl_File_E_None == error) + { + error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir, FURL_DENY_RELATIVE); + rtl_uString_release(dir_url); + } + + if (osl_File_E_None == error) + { + rtl_uString_assign(ppustr_base_dir, dir); + rtl_uString_release(dir); + } + + return error; +} + +/***************************************************************** + * osl_setup_createTempFile_impl + * validate input parameter, setup variables + ****************************************************************/ + + static oslFileError osl_setup_createTempFile_impl_( + rtl_uString* pustrDirectoryURL, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL, + rtl_uString** ppustr_base_dir, + sal_Bool* b_delete_on_close) + { + oslFileError osl_error; + + OSL_PRECOND(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!"); + + if ((0 == pHandle) && (0 == ppustrTempFileURL)) + { + osl_error = osl_File_E_INVAL; + } + else + { + osl_error = osl_setup_base_directory_impl_( + pustrDirectoryURL, ppustr_base_dir); + + *b_delete_on_close = (0 == ppustrTempFileURL); + } + + return osl_error; + } + +/***************************************************************** + * Create a unique file in the specified directory and return + * it's name + ****************************************************************/ + +static oslFileError osl_create_temp_file_impl_( + const rtl_uString* pustr_base_directory, + oslFileHandle* file_handle, + rtl_uString** ppustr_temp_file_name) +{ + rtl_uString* rand_name = 0; + sal_uInt32 len_base_dir = 0; + rtl_uString* tmp_file_path = 0; + rtl_uString* tmp_file_url = 0; + sal_Int32 capacity = 0; + oslFileError osl_error = osl_File_E_None; + sal_Int32 offset_file_name; + const sal_Unicode* puchr; + + OSL_PRECOND(pustr_base_directory, "Invalid Parameter"); + OSL_PRECOND(file_handle, "Invalid Parameter"); + OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter"); + + len_base_dir = rtl_uString_getLength(pustr_base_directory); + + rtl_uStringbuffer_newFromStr_WithLength( + &tmp_file_path, + rtl_uString_getStr((rtl_uString*)pustr_base_directory), + len_base_dir); + + rtl_uStringbuffer_ensureCapacity( + &tmp_file_path, + &capacity, + (len_base_dir + 1 + RAND_NAME_LENGTH)); + + offset_file_name = len_base_dir; + + puchr = rtl_uString_getStr(tmp_file_path); + + /* ensure that the last character is a '\' */ + + if ((sal_Unicode)'\\' != puchr[len_base_dir - 1]) + { + rtl_uStringbuffer_insert_ascii( + &tmp_file_path, + &capacity, + len_base_dir, + "\\", + 1); + + offset_file_name++; + } + + while(1) /* try until success */ + { + osl_gen_random_name_impl_(&rand_name); + + rtl_uStringbuffer_insert( + &tmp_file_path, + &capacity, + offset_file_name, + rtl_uString_getStr(rand_name), + rtl_uString_getLength(rand_name)); + + osl_error = osl_getFileURLFromSystemPath( + tmp_file_path, &tmp_file_url); + + if (osl_File_E_None == osl_error) + { + /* RW permission for the user only! */ + mode_t old_mode = umask(077); + + osl_error = osl_openFile( + tmp_file_url, + file_handle, + osl_File_OpenFlag_Read | + osl_File_OpenFlag_Write | + osl_File_OpenFlag_Create); + + umask(old_mode); + } + + /* in case of error osl_File_E_EXIST we simply try again else we give up */ + + if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST)) + { + if (rand_name) + rtl_uString_release(rand_name); + + if (tmp_file_url) + rtl_uString_release(tmp_file_url); + + break; + } + } /* while(1) */ + + if (osl_File_E_None == osl_error) + rtl_uString_assign(ppustr_temp_file_name, tmp_file_path); + + if (tmp_file_path) + rtl_uString_release(tmp_file_path); + + return osl_error; +} + +/***************************************************************** + * osl_createTempFile + *****************************************************************/ + +oslFileError SAL_CALL osl_createTempFile( + rtl_uString* pustrDirectoryURL, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL) +{ + rtl_uString* base_directory = 0; + rtl_uString* temp_file_name = 0; + oslFileHandle temp_file_handle; + sal_Bool b_delete_on_close; + oslFileError osl_error; + + osl_error = osl_setup_createTempFile_impl_( + pustrDirectoryURL, + pHandle, + ppustrTempFileURL, + &base_directory, + &b_delete_on_close); + + if (osl_File_E_None != osl_error) + return osl_error; + + osl_error = osl_create_temp_file_impl_( + base_directory, &temp_file_handle, &temp_file_name); + + if (osl_File_E_None == osl_error) + { + rtl_uString* temp_file_url = 0; + + /* assuming this works */ + osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url); + + if (b_delete_on_close) + { + osl_error = osl_removeFile(temp_file_url); + + if (osl_File_E_None == osl_error) + *pHandle = temp_file_handle; + else + osl_closeFile(temp_file_handle); + } + else + { + if (pHandle) + *pHandle = temp_file_handle; + else + osl_closeFile(temp_file_handle); + + rtl_uString_assign(ppustrTempFileURL, temp_file_url); + } + + if (temp_file_url) + rtl_uString_release(temp_file_url); + + if (temp_file_name) + rtl_uString_release(temp_file_name); + } + + if (base_directory) + rtl_uString_release(base_directory); + + return osl_error; +} diff --git a/sal/osl/os2/thread.c b/sal/osl/os2/thread.c new file mode 100644 index 000000000000..313e67c0f925 --- /dev/null +++ b/sal/osl/os2/thread.c @@ -0,0 +1,772 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/time.h> +#include <rtl/alloc.h> +#include <rtl/tencinfo.h> + +/* + Thread-data structure hidden behind oslThread: +*/ +typedef struct _osl_TThreadImpl +{ + + TID m_ThreadId; /* identifier for this thread */ + sal_Int32 m_Flags; + HEV m_hEvent; + sal_uInt32 m_Timeout; + oslWorkerFunction m_WorkerFunction; + void* m_pData; + sal_Bool m_StartSuspended; + HAB m_hab; + HMQ m_hmq; + +} osl_TThreadImpl; + +#define THREADIMPL_FLAGS_TERMINATE 0x0001 +#define THREADIMPL_FLAGS_SLEEP 0x0002 + + +// static mutex to control access to private members of oslMutexImpl +static HMTX MutexLock = NULL; + +/*****************************************************************************/ + +HAB osl_getPMinternal_HAB(oslThread hThread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)hThread; + + if(pThreadImpl == NULL) /* valid ptr? */ + { + return NULL; + } + else + { + return pThreadImpl->m_hab; + } +} + +HMQ osl_getPMinternal_HMQ(oslThread hThread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)hThread; + + if(pThreadImpl == NULL) /* valid ptr? */ + { + return NULL; + } + else + { + return pThreadImpl->m_hmq; + } +} + + +/*****************************************************************************/ +/* oslWorkerWrapperFunction */ +/*****************************************************************************/ +static void oslWorkerWrapperFunction(void* pData) +{ + BOOL rc; + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData; + +#if OSL_DEBUG_LEVEL>0 +printf("oslWorkerWrapperFunction pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl, pThreadImpl->m_ThreadId); +#endif + /* Inizialize PM for this thread */ + pThreadImpl->m_hab = WinInitialize( 0 ); +#if OSL_DEBUG_LEVEL>0 +printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hab %x\n", pThreadImpl->m_ThreadId,pThreadImpl->m_hab); +#endif + pThreadImpl->m_hmq = WinCreateMsgQueue( pThreadImpl->m_hab, 0 ); +#if OSL_DEBUG_LEVEL>0 +printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hmq %x\n", pThreadImpl->m_ThreadId,pThreadImpl->m_hmq); +#endif + + /* call worker-function with data */ + pThreadImpl->m_WorkerFunction( pThreadImpl->m_pData ); + + /* Free all PM-resources for this thread */ +#if OSL_DEBUG_LEVEL>0 +printf("pThreadImpl->m_ThreadId %d, about to destroy queue\n", pThreadImpl->m_ThreadId); +#endif + rc = WinDestroyMsgQueue( pThreadImpl->m_hmq ); +#if OSL_DEBUG_LEVEL>0 +printf("pThreadImpl->m_ThreadId %d, WinDestroyMsgQueue rc=%d (should be 1)\n", pThreadImpl->m_ThreadId, rc); +printf("pThreadImpl->m_ThreadId %d, about to terminate hab\n", pThreadImpl->m_ThreadId); +#endif + rc = WinTerminate( pThreadImpl->m_hab ); +#if OSL_DEBUG_LEVEL>0 +printf("pThreadImpl->m_ThreadId %d, WinTerminate rc=%d (should be 1)\n", pThreadImpl->m_ThreadId, rc); +#endif +} + + +/*****************************************************************************/ +/* oslCreateThread */ +/*****************************************************************************/ +static oslThread oslCreateThread(oslWorkerFunction pWorker, + void* pThreadData, + sal_Bool nFlags) +{ + osl_TThreadImpl* pThreadImpl; + + /* alloc mem. for our internal data structure */ + pThreadImpl = (osl_TThreadImpl*)malloc(sizeof(osl_TThreadImpl)); + + OSL_ASSERT(pThreadImpl); + + pThreadImpl->m_WorkerFunction= pWorker; + pThreadImpl->m_pData= pThreadData; + + pThreadImpl->m_Flags = 0; + pThreadImpl->m_hEvent = 0; + pThreadImpl->m_Timeout = 0; + pThreadImpl->m_StartSuspended = nFlags; + pThreadImpl->m_hab = 0; + pThreadImpl->m_hmq = 0; + + if ( nFlags == sal_True ) + { + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + } + + pThreadImpl->m_ThreadId = (TID) _beginthread( oslWorkerWrapperFunction, /* worker-function */ + NULL, /* unused parameter */ + 1024*1024, /* max. Stacksize */ + pThreadImpl ); + if ( nFlags == sal_True ) + { + if( pThreadImpl->m_ThreadId != -1 ) + DosSuspendThread( pThreadImpl->m_ThreadId ); + DosReleaseMutexSem( MutexLock); + } +#if OSL_DEBUG_LEVEL>0 +printf("oslCreateThread pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl, pThreadImpl->m_ThreadId); +#endif + if(pThreadImpl->m_ThreadId == -1) + { + /* create failed */ + if (pThreadImpl->m_hEvent != 0) + DosCloseEventSem(pThreadImpl->m_hEvent); + + free(pThreadImpl); + return 0; + } + + pThreadImpl->m_hEvent= 0; + + return pThreadImpl; + +} + +/*****************************************************************************/ +/* osl_createThread */ +/*****************************************************************************/ +oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker, + void* pThreadData) +{ + return oslCreateThread(pWorker,pThreadData,sal_False); +} + +/*****************************************************************************/ +/* osl_createSuspendedThread */ +/*****************************************************************************/ +oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker, + void* pThreadData) +{ + return oslCreateThread(pWorker,pThreadData,sal_True); +} + +/*****************************************************************************/ +/* osl_getThreadIdentifier */ +/*****************************************************************************/ +oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + if (pThreadImpl != NULL) + return ((oslThreadIdentifier)pThreadImpl->m_ThreadId); + else + { + PTIB pptib = NULL; + PPIB pppib = NULL; + + DosGetInfoBlocks( &pptib, &pppib ); + return ((oslThreadIdentifier) pptib->tib_ptib2->tib2_ultid ); + } +} + +/*****************************************************************************/ +/* osl_destroyThread */ +/*****************************************************************************/ +void SAL_CALL osl_destroyThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + if(Thread == 0) /* valid ptr? */ + { + /* thread already destroyed or not created */ + return; + } + + if(pThreadImpl->m_ThreadId != -1) /* valid handle ? */ + { + /* cancel thread */ + DosKillThread( pThreadImpl->m_ThreadId ); + } +} + +/*****************************************************************************/ +/* osl_freeThreadHandle */ +/*****************************************************************************/ +void SAL_CALL osl_freeThreadHandle(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + if(Thread == 0) /* valid ptr? */ + { + /* thread already destroyed or not created */ + return; + } + + if (pThreadImpl->m_hEvent != 0) + DosCloseEventSem(pThreadImpl->m_hEvent); + + /* free memory */ + free(Thread); +} + +/*****************************************************************************/ +/* osl_resumeThread */ +/*****************************************************************************/ +void SAL_CALL osl_resumeThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + OSL_ASSERT(pThreadImpl); /* valid ptr? */ + + DosResumeThread( pThreadImpl->m_ThreadId ); +} + +/*****************************************************************************/ +/* osl_suspendThread */ +/*****************************************************************************/ +void SAL_CALL osl_suspendThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + OSL_ASSERT(pThreadImpl); /* valid ptr? */ + + DosSuspendThread( pThreadImpl->m_ThreadId ); +} + +/*****************************************************************************/ +/* osl_setThreadPriority */ +/*****************************************************************************/ +void SAL_CALL osl_setThreadPriority(oslThread Thread, + oslThreadPriority Priority) +{ + ULONG nOs2PriorityClass; + ULONG nOs2PriorityDelta; + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + OSL_ASSERT(pThreadImpl); /* valid ptr? */ + + switch(Priority) { + + case osl_Thread_PriorityHighest: + + nOs2PriorityClass = PRTYC_REGULAR; + nOs2PriorityDelta = PRTYD_MAXIMUM; + break; + + case osl_Thread_PriorityAboveNormal: + + nOs2PriorityClass = PRTYC_REGULAR; + nOs2PriorityDelta = 16; + break; + + case osl_Thread_PriorityNormal: + + nOs2PriorityClass = PRTYC_REGULAR; + nOs2PriorityDelta = 0; + break; + + case osl_Thread_PriorityBelowNormal: + + nOs2PriorityClass = PRTYC_REGULAR; + nOs2PriorityDelta = -16; + break; + + case osl_Thread_PriorityLowest: + + nOs2PriorityClass = PRTYC_REGULAR; + nOs2PriorityDelta = PRTYD_MINIMUM; + break; + + case osl_Thread_PriorityUnknown: + OSL_ASSERT(FALSE); /* only fools try this...*/ + + /* let release-version behave friendly */ + return; + + default: + OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/ + + /* let release-version behave friendly */ + return; + } + + DosSetPriority( PRTYS_THREAD, + nOs2PriorityClass, nOs2PriorityDelta, + pThreadImpl->m_ThreadId ); + +} + +/*****************************************************************************/ +/* osl_getThreadPriority */ +/*****************************************************************************/ + +#define BYTE1FROMULONG(ul) ((UCHAR) (ul)) +#define BYTE2FROMULONG(ul) ((UCHAR) ((ULONG) ul >> 8)) + +oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread) +{ + ULONG nOs2PriorityClass; + ULONG nOs2PriorityDelta; + + oslThreadPriority Priority; + + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + /* invalid arguments ?*/ + if(pThreadImpl==0 || pThreadImpl->m_ThreadId==-1) + { + return osl_Thread_PriorityUnknown; + } + + /* get current priorities */ + { + PTIB pptib = NULL; + PPIB pppib = NULL; + + DosGetInfoBlocks( &pptib, &pppib ); + nOs2PriorityClass = BYTE1FROMULONG( pptib->tib_ptib2->tib2_ulpri ); + nOs2PriorityDelta = BYTE2FROMULONG( pptib->tib_ptib2->tib2_ulpri ); + } + + /* map OS2 priority to enum */ + switch(nOs2PriorityClass) + { + case PRTYC_TIMECRITICAL: + Priority= osl_Thread_PriorityHighest; + break; + + case PRTYC_REGULAR: + + if( nOs2PriorityDelta == 0 ) + { + Priority= osl_Thread_PriorityNormal; + break; + } + + if( nOs2PriorityDelta < -16 ) + { + Priority= osl_Thread_PriorityLowest; + break; + } + + if( nOs2PriorityDelta < 0 ) + { + Priority= osl_Thread_PriorityBelowNormal; + break; + } + + if( nOs2PriorityDelta > 0 ) + { + Priority= osl_Thread_PriorityAboveNormal; + break; + } + + Priority= osl_Thread_PriorityHighest; + break; + + case PRTYC_IDLETIME: + Priority= osl_Thread_PriorityLowest; + break; + + default: + OSL_ASSERT(FALSE); /* OS/2 API changed, incorporate new prio-level! */ + + /* release-version behaves friendly */ + Priority= osl_Thread_PriorityUnknown; + } + + return Priority; +} + +/*****************************************************************************/ +/* osl_isThreadRunning */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + APIRET rc; + + /* invalid arguments ?*/ + if(pThreadImpl==0 || pThreadImpl->m_ThreadId==-1) + { + return sal_False; + } + + if( osl_getThreadIdentifier( 0 ) == osl_getThreadIdentifier( Thread ) ) + return sal_True; + + rc = DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_NOWAIT ); + + return( rc != ERROR_INVALID_THREADID ); +} + +/*****************************************************************************/ +/* osl_joinWithThread */ +/*****************************************************************************/ +void SAL_CALL osl_joinWithThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + /* invalid arguments?*/ + if(pThreadImpl==0 || pThreadImpl->m_ThreadId==-1) + { + /* assume thread is not running */ + return; + } + + DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_WAIT ); +} + +/*****************************************************************************/ +/* osl_waitThread */ +/*****************************************************************************/ +void SAL_CALL osl_waitThread(const TimeValue* pDelay) +{ + int millisecs; + + OSL_ASSERT(pDelay); + + millisecs = pDelay->Seconds * 1000 + pDelay->Nanosec / 1000000; + + DosSleep(millisecs); +} + +/*****************************************************************************/ +/* osl_terminateThread */ +/*****************************************************************************/ +void SAL_CALL osl_terminateThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + /* invalid arguments?*/ + if (pThreadImpl==0 || pThreadImpl->m_ThreadId==-1) + { + /* assume thread is not running */ + return; + } + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + pThreadImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE; + DosReleaseMutexSem( MutexLock); +} + + +/*****************************************************************************/ +/* osl_scheduleThread */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + osl_yieldThread(); + + /* invalid arguments?*/ + if (pThreadImpl==0 || pThreadImpl->m_ThreadId==-1) + { + /* assume thread is not running */ + return sal_False; + } + + if (pThreadImpl->m_Flags & THREADIMPL_FLAGS_SLEEP) + { + OSL_ASSERT (pThreadImpl->m_hEvent != 0); + + DosWaitEventSem(pThreadImpl->m_hEvent, pThreadImpl->m_Timeout); + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + + pThreadImpl->m_Timeout = 0; + + pThreadImpl->m_Flags &= ~THREADIMPL_FLAGS_SLEEP; + + DosReleaseMutexSem( MutexLock); + } + + return ((pThreadImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) == 0); +} + +/*****************************************************************************/ +/* osl_yieldThread */ +/*****************************************************************************/ +void SAL_CALL osl_yieldThread() +{ + DosSleep(0); +} + +typedef struct _TLS +{ + PULONG pulPtr; + oslThreadKeyCallbackFunction pfnCallback; + struct _TLS *pNext, *pPrev; +} TLS, *PTLS; + +static PTLS g_pThreadKeyList = NULL; + +static void AddKeyToList( PTLS pTls ) +{ + if ( pTls ) + { + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + + pTls->pNext = g_pThreadKeyList; + pTls->pPrev = 0; + + if ( g_pThreadKeyList ) + g_pThreadKeyList->pPrev = pTls; + + g_pThreadKeyList = pTls; + + DosReleaseMutexSem( MutexLock); + } +} + +static void RemoveKeyFromList( PTLS pTls ) +{ + if ( pTls ) + { + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + if ( pTls->pPrev ) + pTls->pPrev->pNext = pTls->pNext; + else + { + OSL_ASSERT( pTls == g_pThreadKeyList ); + g_pThreadKeyList = pTls->pNext; + } + + if ( pTls->pNext ) + pTls->pNext->pPrev = pTls->pPrev; + DosReleaseMutexSem( MutexLock); + } +} + +void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void) +{ + PTLS pTls; + + DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); + pTls = g_pThreadKeyList; + while ( pTls ) + { + if ( pTls->pfnCallback ) + { + void *pValue = (void*)*pTls->pulPtr; + + if ( pValue ) + pTls->pfnCallback( pValue ); + } + + pTls = pTls->pNext; + } + DosReleaseMutexSem( MutexLock); +} + +/*****************************************************************************/ +/* osl_createThreadKey */ +/*****************************************************************************/ +oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback) +{ + PTLS pTls = (PTLS)rtl_allocateMemory( sizeof(TLS) ); + + if ( pTls ) + { + pTls->pfnCallback = pCallback; + if (DosAllocThreadLocalMemory(1, &pTls->pulPtr) != NO_ERROR) + { + rtl_freeMemory( pTls ); + pTls = 0; + } + else + { + *pTls->pulPtr = 0; + AddKeyToList( pTls ); + } + } + + return ((oslThreadKey)pTls); +} + +/*****************************************************************************/ +/* osl_destroyThreadKey */ +/*****************************************************************************/ +void SAL_CALL osl_destroyThreadKey(oslThreadKey Key) +{ + if (Key != 0) + { + PTLS pTls = (PTLS)Key; + + RemoveKeyFromList( pTls ); + DosFreeThreadLocalMemory(pTls->pulPtr); + rtl_freeMemory( pTls ); + } +} + +/*****************************************************************************/ +/* osl_getThreadKeyData */ +/*****************************************************************************/ +void * SAL_CALL osl_getThreadKeyData(oslThreadKey Key) +{ + if (Key != 0) + { + PTLS pTls = (PTLS)Key; + + return ((void *) *pTls->pulPtr); + } + + return (NULL); +} + +/*****************************************************************************/ +/* osl_setThreadKeyData */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData) +{ + if (Key != 0) + { + PTLS pTls = (PTLS)Key; + void* pOldData = NULL; + BOOL fSuccess = TRUE; //YD cannot fail + + if ( pTls->pfnCallback ) + pOldData = (void*)*pTls->pulPtr; + + *pTls->pulPtr = (ULONG)pData; + + if ( fSuccess && pTls->pfnCallback && pOldData ) + pTls->pfnCallback( pOldData ); + + return (sal_Bool)(fSuccess != FALSE); + } + + return (sal_False); +} + + + +/*****************************************************************************/ +/* osl_getThreadTextEncoding */ +/*****************************************************************************/ + +ULONG g_dwTLSTextEncodingIndex = (ULONG)-1; + +sal_uInt32 SAL_CALL _GetACP( void) +{ + APIRET rc; + ULONG aulCpList[8] = {0}; + ULONG ulListSize; + + rc = DosQueryCp( sizeof( aulCpList), aulCpList, &ulListSize); + if (rc) + return 437; // in case of error, return codepage EN_US + // current codepage is first of list, others are the prepared codepages. + return aulCpList[0]; +} + +rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void) +{ + rtl_TextEncoding _encoding; + + if ( (ULONG)-1 == g_dwTLSTextEncodingIndex ) { + rtl_TextEncoding defaultEncoding; + const char * pszEncoding; + + /* create thread specific data key */ + g_dwTLSTextEncodingIndex = osl_createThreadKey( NULL); + + /* determine default text encoding */ + pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING"); + if (pszEncoding) + defaultEncoding = atoi(pszEncoding); + else + defaultEncoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP()); + + //OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW); + //g_thread.m_textencoding.m_default = defaultEncoding; + osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)defaultEncoding); + } + + _encoding = (rtl_TextEncoding)osl_getThreadKeyData( g_dwTLSTextEncodingIndex ); + if (0 == _encoding) { + const char * pszEncoding; + /* determine default text encoding */ + pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING"); + if (pszEncoding) + _encoding = atoi(pszEncoding); + else + _encoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP()); + /* save for future reference */ + osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)_encoding); + } + + return _encoding; +} + +/*****************************************************************************/ +/* osl_getThreadTextEncoding */ +/*****************************************************************************/ +rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding ) +{ + rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding(); + + osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)Encoding); + + return oldEncoding; +} + + + diff --git a/sal/osl/os2/time.c b/sal/osl/os2/time.c new file mode 100644 index 000000000000..c1a98a6b87a9 --- /dev/null +++ b/sal/osl/os2/time.c @@ -0,0 +1,269 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/time.h> + +/* FIXME: detection should be done in configure script */ +#if defined(MACOSX) || defined(FREEBSD) || defined(NETBSD) || defined(LINUX) +#define STRUCT_TM_HAS_GMTOFF 1 + +#elif defined(SOLARIS) +#define HAS_ALTZONE 1 +#endif + +/*-------------------------------------------------- + * osl_getSystemTime + *-------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getSystemTime(TimeValue* TimeValue) +{ + struct timeval tp; + + /* FIXME: use higher resolution */ + gettimeofday(&tp, NULL); + + TimeValue->Seconds = tp.tv_sec; + TimeValue->Nanosec = tp.tv_usec * 1000; + + return (sal_True); +} + + +/*-------------------------------------------------- + * osl_getDateTimeFromTimeValue + *-------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getDateTimeFromTimeValue( TimeValue* pTimeVal, oslDateTime* pDateTime ) +{ + struct tm *pSystemTime; + struct tm tmBuf; + time_t atime; + + atime = (time_t)pTimeVal->Seconds; + + /* Convert time from type time_t to struct tm */ + pSystemTime = gmtime_r( &atime, &tmBuf ); + + + /* Convert struct tm to struct oslDateTime */ + if ( pSystemTime != NULL ) + { + pDateTime->NanoSeconds = pTimeVal->Nanosec; + pDateTime->Seconds = pSystemTime->tm_sec; + pDateTime->Minutes = pSystemTime->tm_min; + pDateTime->Hours = pSystemTime->tm_hour; + pDateTime->Day = pSystemTime->tm_mday; + pDateTime->DayOfWeek = pSystemTime->tm_wday; + pDateTime->Month = pSystemTime->tm_mon + 1; + pDateTime->Year = pSystemTime->tm_year + 1900; + + return sal_True; + } + + return sal_False; +} + +/*-------------------------------------------------- + * osl_getTimeValueFromDateTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getTimeValueFromDateTime( oslDateTime* pDateTime, TimeValue* pTimeVal ) +{ + struct tm aTime; + time_t nSeconds; + + /* Convert struct oslDateTime to struct tm */ + aTime.tm_sec = pDateTime->Seconds; + aTime.tm_min = pDateTime->Minutes; + aTime.tm_hour = pDateTime->Hours; + aTime.tm_mday = pDateTime->Day; + aTime.tm_wday = pDateTime->DayOfWeek; + + if ( pDateTime->Month > 0 ) + aTime.tm_mon = pDateTime->Month - 1; + else + return sal_False; + + if ( pDateTime->Year >= 1900 ) + aTime.tm_year = pDateTime->Year - 1900; + else + return sal_False; + + aTime.tm_isdst = -1; + aTime.tm_wday = 0; + aTime.tm_yday = 0; + + /* Convert time to calendar value */ + nSeconds = mktime( &aTime ); + + /* + * mktime expects the struct tm to be in local timezone, so we have to adjust + * the returned value to be timezone neutral. + */ + + if ( nSeconds != (time_t) -1 ) + { + time_t bias; + + /* timezone corrections */ + tzset(); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - aTime.tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = aTime.tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = aTime.tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + pTimeVal->Seconds = nSeconds; + pTimeVal->Nanosec = pDateTime->NanoSeconds; + + if ( nSeconds > bias ) + pTimeVal->Seconds -= bias; + + return sal_True; + } + + return sal_False; +} + + +/*-------------------------------------------------- + * osl_getLocalTimeFromSystemTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getLocalTimeFromSystemTime( TimeValue* pSystemTimeVal, TimeValue* pLocalTimeVal ) +{ + struct tm *pLocalTime; + struct tm tmBuf; + time_t bias; + time_t atime; + + atime = (time_t) pSystemTimeVal->Seconds; + pLocalTime = localtime_r( &atime, &tmBuf ); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - pLocalTime->tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = pLocalTime->tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = pLocalTime->tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + if ( (sal_Int64) pSystemTimeVal->Seconds > bias ) + { + pLocalTimeVal->Seconds = pSystemTimeVal->Seconds - bias; + pLocalTimeVal->Nanosec = pSystemTimeVal->Nanosec; + + return sal_True; + } + + return sal_False; +} + +/*-------------------------------------------------- + * osl_getSystemTimeFromLocalTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getSystemTimeFromLocalTime( TimeValue* pLocalTimeVal, TimeValue* pSystemTimeVal ) +{ + struct tm *pLocalTime; + struct tm tmBuf; + time_t bias; + time_t atime; + + atime = (time_t) pLocalTimeVal->Seconds; + + /* Convert atime, which is a local time, to it's GMT equivalent. Then, get + * the timezone offset for the local time for the GMT equivalent time. Note + * that we cannot directly use local time to determine the timezone offset + * because GMT is the only reliable time that we can determine timezone + * offset from. + */ + + atime = mktime( gmtime_r( &atime, &tmBuf ) ); + pLocalTime = localtime_r( &atime, &tmBuf ); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - pLocalTime->tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = pLocalTime->tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = pLocalTime->tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + if ( (sal_Int64) pLocalTimeVal->Seconds + bias > 0 ) + { + pSystemTimeVal->Seconds = pLocalTimeVal->Seconds + bias; + pSystemTimeVal->Nanosec = pLocalTimeVal->Nanosec; + + return sal_True; + } + + return sal_False; +} + + + +static struct timeval startTime; +static sal_Bool bGlobalTimer = sal_False; + +sal_uInt32 SAL_CALL osl_getGlobalTimer() +{ + struct timeval currentTime; + sal_uInt32 nSeconds; + + // FIXME: not thread safe !! + if ( bGlobalTimer == sal_False ) + { + gettimeofday( &startTime, NULL ); + bGlobalTimer=sal_True; + } + + gettimeofday( ¤tTime, NULL ); + + nSeconds = (sal_uInt32)( currentTime.tv_sec - startTime.tv_sec ); + + return ( nSeconds * 1000 ) + (long) (( currentTime.tv_usec - startTime.tv_usec) / 1000 ); +} diff --git a/sal/osl/os2/util.c b/sal/osl/os2/util.c new file mode 100644 index 000000000000..cfe3eb76c622 --- /dev/null +++ b/sal/osl/os2/util.c @@ -0,0 +1,37 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/util.h" + + + +extern sal_Bool osl_getEthernetAddress( sal_uInt8 * pTargetAddress ) +{ + return sal_False; +} + + diff --git a/sal/osl/os2/uunxapi.cxx b/sal/osl/os2/uunxapi.cxx new file mode 100644 index 000000000000..e86ad31264e0 --- /dev/null +++ b/sal/osl/os2/uunxapi.cxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _LIMITS_H + #include <limits.h> + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + #ifndef _OSL_THREAD_H_ + #include <osl/thread.h> + #endif + + #ifndef _OSL_UUNXAPI_HXX_ + #include "uunxapi.hxx" + #endif + + //########################### + //access_u + int access_u(const rtl_uString* pustrPath, int mode) + { + return access(OUStringToOString(pustrPath).getStr(), mode); + } + + //######################### + //realpath_u + sal_Bool realpath_u(const rtl_uString* pustrFileName, rtl_uString** ppustrResolvedName) + { + rtl::OString fn = rtl::OUStringToOString( + rtl::OUString(const_cast<rtl_uString*>(pustrFileName)), + osl_getThreadTextEncoding()); + + char rp[PATH_MAX]; + bool bRet = realpath(fn.getStr(), rp); + + if (bRet) + { + rtl::OUString resolved = rtl::OStringToOUString( + rtl::OString(static_cast<sal_Char*>(rp)), + osl_getThreadTextEncoding()); + + rtl_uString_assign(ppustrResolvedName, resolved.pData); + } + return bRet; + } + + //######################### + //lstat_u + int lstat_u(const rtl_uString* pustrPath, struct stat* buf) + { + return lstat(OUStringToOString(pustrPath).getStr(), buf); + } + + //######################### + // @see mkdir + int mkdir_u(const rtl_uString* path, mode_t mode) + { + return mkdir(OUStringToOString(path).getStr(), mode); + } + diff --git a/sal/osl/os2/uunxapi.h b/sal/osl/os2/uunxapi.h new file mode 100644 index 000000000000..9eddc5fe4753 --- /dev/null +++ b/sal/osl/os2/uunxapi.h @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_UUNXAPI_H_ + #define _OSL_UUNXAPI_H_ + + #ifndef _UNISTD_H + #include <unistd.h> + #endif + + #ifndef _STDLIB_H + #include <stdlib.h> + #endif + + #ifndef _TYPES_H + #include <sys/types.h> + #endif + + #ifndef _STAT_H + #include <sys/stat.h> + #endif + + #ifndef _RTL_USTRING_H_ + #include <rtl/ustring.h> + #endif + + + #ifdef __cplusplus + extern "C" + { + #endif + + /* @see access */ + int access_u(const rtl_uString* pustrPath, int mode); + + /*********************************** + @descr + The return value differs from the + realpath function + + @returns sal_True on success else + sal_False + + @see realpath + **********************************/ + sal_Bool realpath_u( + const rtl_uString* pustrFileName, + rtl_uString** ppustrResolvedName); + + /* @see lstat */ + int lstat_u(const rtl_uString* pustrPath, struct stat* buf); + + /* @see mkdir */ + int mkdir_u(const rtl_uString* path, mode_t mode); + + #ifdef __cplusplus + } + #endif + + + #endif /* _OSL_UUNXAPI_H_ */ + diff --git a/sal/osl/os2/uunxapi.hxx b/sal/osl/os2/uunxapi.hxx new file mode 100644 index 000000000000..ab7e5cce890d --- /dev/null +++ b/sal/osl/os2/uunxapi.hxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_UUNXAPI_HXX_ + #define _OSL_UUNXAPI_HXX_ + + #ifndef _OSL_UUNXAPI_H_ + #include "uunxapi.h" + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + //########################### + inline rtl::OString OUStringToOString(const rtl_uString* s) + { + return rtl::OUStringToOString( + rtl::OUString(const_cast<rtl_uString*>(s)), + osl_getThreadTextEncoding()); + } + + namespace osl + { + + /*********************************** + osl::access + + @see access + **********************************/ + + inline int access(const rtl::OUString& ustrPath, int mode) + { + return access_u(ustrPath.pData, mode); + } + + /*********************************** + osl::realpath + + @descr + The return value differs from the + realpath function + + @returns sal_True on success else + sal_False + + @see realpath + **********************************/ + + inline sal_Bool realpath( + const rtl::OUString& ustrFileName, + rtl::OUString& ustrResolvedName) + { + return realpath_u(ustrFileName.pData, &ustrResolvedName.pData); + } + + + /*********************************** + osl::lstat + + @see lstat + **********************************/ + + inline int lstat(const rtl::OUString& ustrPath, struct stat& buf) + { + return lstat_u(ustrPath.pData, &buf); + } + + /*********************************** + osl::mkdir + @see mkdir + **********************************/ + inline int mkdir(const rtl::OUString& aPath, mode_t aMode) + { + return mkdir_u(aPath.pData, aMode); + } + + } // end namespace osl + + + #endif /* _OSL_UUNXAPI_HXX_ */ + diff --git a/sal/osl/unx/asm/interlck_sparc.s b/sal/osl/unx/asm/interlck_sparc.s new file mode 100644 index 000000000000..a33e3539398e --- /dev/null +++ b/sal/osl/unx/asm/interlck_sparc.s @@ -0,0 +1,267 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/* + * Implements osl_[increment|decrement]InterlockedCount in two ways: + * sparcv8 architecture: use the "swap" instruction + * sparcv9/sparcv8plus architecture: use the "cas" instruction + * + * 32 bit mode with v8 and v8plus support: + * Initialize once with osl_InterlockedCountSetV9(int bv9) if you want to + * use the "cas" instruction, which is faster (no spinlock needed) + * Default is to use the "swap" instruction, which works on all supported + * SPARC cpu's + * + * osl_InterlockedCountSetV9(int bv9) + * bv9 = 0 use sparcv8 "swap" (spinlock) + * bv9 = 1 use sparcv9/sparcv8plus "cas" (no spinlock) + * + * 32 bit mode without v8 support (implies v8plus) or 64 bit mode: + * No need (nor the possibilty) to call osl_InterlockedCountSetV9(), + * sparcv9 mode is implied. Assemble with -xarch=v8plus (32 bit) or + * -xarch=v9 (64 bit). + * + */ + +#if !defined(__sparcv8plus) && !defined(__sparcv9) && !defined(__sparc_v9__) + +.section ".data" +.align 4 +osl_incrementInterLockCountFuncPtr: +.word osl_incrementInterlockedCountV8 +.type osl_incrementInterLockCountFuncPtr,#object +.size osl_incrementInterLockCountFuncPtr,4 + +.align 4 +osl_decrementInterLockCountFuncPtr: +.word osl_decrementInterlockedCountV8 +.type osl_decrementInterLockCountFuncPtr,#object +.size osl_decrementInterLockCountFuncPtr,4 + +.section ".text" + +#if defined(NETBSD) || defined(LINUX) +/* add the address of the calling "call" instruction (stored in %o7) to + * %o5 which contains _GLOBAL_OFFSET_TABLE_ + */ +.Laddoseven: + retl + add %o7, %o5, %o5 +#endif + + .global osl_incrementInterlockedCount + .align 4 + +osl_incrementInterlockedCount: + +#if defined(NETBSD) || defined(LINUX) + mov %o7, %g1 + sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %o5 + call .Laddoseven + add %o5, %lo(_GLOBAL_OFFSET_TABLE_+4), %o5 + mov %g1, %o7 +#endif + set osl_incrementInterLockCountFuncPtr, %o1 +#if defined(NETBSD) + ld [%o1 + %o5], %o1 +#endif + ld [%o1], %o1 + jmp %o1 + nop ! delay slot + .type osl_incrementInterlockedCount,#function + .size osl_incrementInterlockedCount,.-osl_incrementInterlockedCount + +.section ".text" + .global osl_decrementInterlockedCount + .align 4 + +osl_decrementInterlockedCount: + +#if defined(NETBSD) || defined(LINUX) + mov %o7, %g1 + sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %o5 + call .Laddoseven + add %o5, %lo(_GLOBAL_OFFSET_TABLE_+4), %o5 + mov %g1, %o7 +#endif + set osl_decrementInterLockCountFuncPtr, %o1 +#if defined(NETBSD) || defined(LINUX) + ld [%o1 + %o5], %o1 +#endif + ld [%o1], %o1 + jmp %o1 + nop ! delay slot + .type osl_decrementInterlockedCount,#function + .size osl_decrementInterlockedCount,.-osl_decrementInterlockedCount + +.section ".text" + .global osl_InterlockedCountSetV9 + .align 4 + +osl_InterlockedCountSetV9: + +#if defined(NETBSD) || defined(LINUX) + mov %o7, %g1 + sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %o5 + call .Laddoseven + add %o5, %lo(_GLOBAL_OFFSET_TABLE_+4), %o5 + mov %g1, %o7 +#endif + set osl_incrementInterLockCountFuncPtr, %o1 + set osl_decrementInterLockCountFuncPtr, %o2 + cmp %o0, %g0 + bnz 1f + nop ! delay slot + set osl_incrementInterlockedCountV8, %o0 + set osl_decrementInterlockedCountV8, %o3 +#if defined(NETBSD) || defined(LINUX) + ld [%o0 + %o5], %o0 + ld [%o1 + %o5], %o1 + ld [%o2 + %o5], %o2 + ld [%o3 + %o5], %o3 +#endif + st %o3,[%o2] + retl + st %o0,[%o1] +1: set osl_incrementInterlockedCountV9, %o0 + set osl_decrementInterlockedCountV9, %o3 +#if defined(NETBSD) || defined(LINUX) + ld [%o0 + %o5], %o0 + ld [%o1 + %o5], %o1 + ld [%o2 + %o5], %o2 + ld [%o3 + %o5], %o3 +#endif + st %o3,[%o2] + retl + st %o0,[%o1] + + .type osl_InterlockedCountSetV9,#function + .size osl_InterlockedCountSetV9,.-osl_InterlockedCountSetV9 + + +.section ".text" + .local osl_incrementInterlockedCountV8 + .align 4 + +! Implements osl_[increment|decrement]InterlockedCount with sparcv8 "swap" instruction. +! Uses -4096 as lock value for spinlock to allow for small negative counts. + +osl_incrementInterlockedCountV8: + +1: ld [%o0], %o1 + cmp %o1, -4096 ! test spinlock + be 1b + mov -4096, %o1 ! delay slot + swap [%o0], %o1 + cmp %o1, -4096 + be 1b + inc %o1 ! delay slot, if we got spinlock, increment count + st %o1, [%o0] + retl + mov %o1, %o0 ! delay slot + + .type osl_incrementInterlockedCountV8,#function + .size osl_incrementInterlockedCountV8,.-osl_incrementInterlockedCountV8 + + +.section ".text" + .local osl_decrementInterlockedCountV8 + .align 4 + +osl_decrementInterlockedCountV8: + +1: ld [%o0], %o1 + cmp %o1, -4096 ! test spinlock + be 1b + mov -4096, %o1 ! delay slot + swap [%o0], %o1 + cmp %o1, -4096 + be 1b + dec %o1 ! delay slot, if we got spinlock, decrement count + st %o1, [%o0] ! delay slot + retl + mov %o1, %o0 ! delay slot + + .type osl_decrementInterlockedCountV8,#function + .size osl_decrementInterlockedCountV8,.-osl_decrementInterlockedCountV8 + +#endif /* !__sparcv8plus && !__sparcv9 && !_sparcv9__ */ + +.section ".text" +#if defined(__sparcv8plus) || defined(__sparcv9) || defined(__sparc_v9__) +#define osl_incrementInterlockedCountV9 osl_incrementInterlockedCount + .global osl_incrementInterlockedCountV9 +#else + .local osl_incrementInterlockedCountV9 +#endif + .align 8 + +! Implements osl_[increment|decrement]InterlockedCount with sparcv9(sparcv8plus) "cas" +! instruction. + +osl_incrementInterlockedCountV9: + +1: ld [%o0], %o1 + add %o1, 1, %o2 +! allow linux to build for v8 + .word 0xD5E21009 +! cas [%o0], %o1, %o2 + cmp %o1, %o2 + bne 1b + nop ! delay slot + retl + add %o2, 1, %o0 ! delay slot + + .type osl_incrementInterlockedCountV9,#function + .size osl_incrementInterlockedCountV9,.-osl_incrementInterlockedCountV9 + + +.section ".text" +#if defined(__sparcv8plus) || defined(__sparcv9) || defined(__sparc_v9__) +#define osl_decrementInterlockedCountV9 osl_decrementInterlockedCount + .global osl_decrementInterlockedCountV9 +#else + .local osl_decrementInterlockedCountV9 +#endif + .align 8 + +osl_decrementInterlockedCountV9: + +1: ld [%o0], %o1 + sub %o1, 1, %o2 +! allow linux to build for v8 + .word 0xD5E21009 +! cas [%o0], %o1, %o2 + cmp %o1, %o2 + bne 1b + nop ! delay slot + retl + sub %o2, 1, %o0 ! delay slot + + .type osl_decrementInterlockedCountV9,#function + .size osl_decrementInterlockedCountV9,.-osl_decrementInterlockedCountV9 diff --git a/sal/osl/unx/asm/interlck_x86.s b/sal/osl/unx/asm/interlck_x86.s new file mode 100644 index 000000000000..c1f99008d406 --- /dev/null +++ b/sal/osl/unx/asm/interlck_x86.s @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +.section .text,"ax" + .globl osl_incrementInterlockedCount + +osl_incrementInterlockedCount: + + push %ebp + mov %esp,%ebp + push %ebx + call 1f +1: + pop %ebx + add $_GLOBAL_OFFSET_TABLE_+0x1,%ebx + mov 8(%ebp),%ecx + mov $1,%eax + mov osl_isSingleCPU@GOT(%ebx),%edx + cmp $0,(%edx) + je 2f + xadd %eax,(%ecx) + jmp 3f +2: + lock + xadd %eax,(%ecx) +3: + inc %eax + pop %ebx + mov %ebp,%esp + pop %ebp + ret + + .type osl_incrementInterlockedCount,@function + .size osl_incrementInterlockedCount,.-osl_incrementInterlockedCount + +.section .text,"ax" + .globl osl_decrementInterlockedCount + +osl_decrementInterlockedCount: + + push %ebp + mov %esp,%ebp + push %ebx + call 1f +1: + pop %ebx + add $_GLOBAL_OFFSET_TABLE_+0x1,%ebx + mov 8(%ebp),%ecx + orl $-1,%eax + mov osl_isSingleCPU@GOT(%ebx),%edx + cmp $0,(%edx) + je 2f + xadd %eax,(%ecx) + jmp 3f +2: + lock + xadd %eax,(%ecx) +3: + dec %eax + pop %ebx + mov %ebp,%esp + pop %ebp + ret + + .type osl_decrementInterlockedCount,@function + .size osl_decrementInterlockedCount,.-osl_decrementInterlockedCount + diff --git a/sal/osl/unx/backtrace.c b/sal/osl/unx/backtrace.c new file mode 100755 index 000000000000..00156b80f1d6 --- /dev/null +++ b/sal/osl/unx/backtrace.c @@ -0,0 +1,359 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#ifdef SOLARIS + +#include <dlfcn.h> +#include <pthread.h> +#include <setjmp.h> +#include <stdio.h> +#include <sys/frame.h> +#include "backtrace.h" + +#if defined(SPARC) + +#if defined IS_LP64 + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0x7ff + +#else + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0 + +#endif + +#elif defined( INTEL ) + +#define FRAME_PTR_OFFSET 3 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0 + +#else + +#error Unknown Solaris target platform. + +#endif /* defined SPARC or INTEL */ + + +int backtrace( void **buffer, int max_frames ) +{ + jmp_buf ctx; + long fpval; + struct frame *fp; + int i; + + /* flush register windows */ +#ifdef SPARC + asm("ta 3"); +#endif + + /* get stack- and framepointer */ + setjmp(ctx); + + fpval = ((long*)(ctx))[FRAME_PTR_OFFSET]; + fp = (struct frame*)((char*)(fpval) + STACK_BIAS); + + for (i = 0; (i < FRAME_OFFSET) && (fp != 0); i++) + fp = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); + + /* iterate through backtrace */ + for (i = 0; (fp != 0) && (fp->fr_savpc != 0) && (i < max_frames); i++) + { + /* saved (prev) frame */ + struct frame * prev = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); + + /* store frame */ + *(buffer++) = (void*)(fp->fr_savpc); + + /* prev frame (w/ stack growing top down) */ + fp = (prev > fp) ? prev : 0; + } + + /* return number of frames stored */ + return i; +} + +void backtrace_symbols_fd( void **buffer, int size, int fd ) +{ + FILE *fp = fdopen( fd, "w" ); + + if ( fp ) + { + void **pFramePtr; + + for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- ) + { + Dl_info dli; + ptrdiff_t offset; + + if ( 0 != dladdr( *pFramePtr, &dli ) ) + { + if ( dli.dli_fname && dli.dli_fbase ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase; + fprintf( fp, "%s+0x%x", dli.dli_fname, offset ); + } + if ( dli.dli_sname && dli.dli_saddr ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr; + fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset ); + } + } + fprintf( fp, "[0x%x]\n", *pFramePtr ); + } + + fflush( fp ); + fclose( fp ); + } +} + +#endif /* defined SOLARIS */ + + +#if defined FREEBSD || defined NETBSD +#include <dlfcn.h> +#include <pthread.h> +#include <setjmp.h> +#include <stddef.h> +#include <stdio.h> +#include "backtrace.h" + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 + +int backtrace( void **buffer, int max_frames ) +{ + struct frame *fp; + jmp_buf ctx; + int i; + /* get stack- and framepointer */ + setjmp(ctx); + fp = (struct frame*)(((size_t*)(ctx))[FRAME_PTR_OFFSET]); + for ( i=0; (i<FRAME_OFFSET) && (fp!=0); i++) + fp = fp->fr_savfp; + /* iterate through backtrace */ + for (i=0; fp && fp->fr_savpc && i<max_frames; i++) + { + /* store frame */ + *(buffer++) = (void *)fp->fr_savpc; + /* next frame */ + fp=fp->fr_savfp; + } + return i; +} + +void backtrace_symbols_fd( void **buffer, int size, int fd ) +{ + FILE *fp = fdopen( fd, "w" ); + + if ( fp ) + { + void **pFramePtr; + for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- ) + { + Dl_info dli; + ptrdiff_t offset; + + if ( 0 != dladdr( *pFramePtr, &dli ) ) + { + if ( dli.dli_fname && dli.dli_fbase ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase; + fprintf( fp, "%s+0x%x", dli.dli_fname, offset ); + } + if ( dli.dli_sname && dli.dli_saddr ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr; + fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset ); + } + } + fprintf( fp, "[0x%x]\n", *pFramePtr ); + } + fflush( fp ); + fclose( fp ); + } +} +#endif /* defined FREEBSD */ + +#ifdef LINUX + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <dlfcn.h> +#include <pthread.h> +#include <setjmp.h> +#include <stdio.h> +#include "backtrace.h" + +#if defined(SPARC) + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 + +#else + +#error Unknown Linux target platform. + +#endif /* defined SPARC or INTEL */ + +typedef int ptrdiff_t; + +int backtrace( void **buffer, int max_frames ) +{ + struct frame *fp; + jmp_buf ctx; + int i; + + /* flush register windows */ +#ifdef SPARC + asm("ta 3"); +#endif + /* get stack- and framepointer */ + setjmp(ctx); + fp = (struct frame*)(((size_t*)(ctx))[FRAME_PTR_OFFSET]); + for ( i=0; (i<FRAME_OFFSET) && (fp!=0); i++) + fp = fp->fr_savfp; + + /* iterate through backtrace */ + for (i=0; fp && fp->fr_savpc && i<max_frames; i++) + { + /* store frame */ + *(buffer++) = (void *)fp->fr_savpc; + /* next frame */ + fp=fp->fr_savfp; + } + return i; +} + +void backtrace_symbols_fd( void **buffer, int size, int fd ) +{ + FILE *fp = fdopen( fd, "w" ); + + if ( fp ) + { + void **pFramePtr; + + for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- ) + { + Dl_info dli; + ptrdiff_t offset; + + if ( 0 != dladdr( *pFramePtr, &dli ) ) + { + if ( dli.dli_fname && dli.dli_fbase ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase; + fprintf( fp, "%s+0x%x", dli.dli_fname, offset ); + } + if ( dli.dli_sname && dli.dli_saddr ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr; + fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset ); + } + } + fprintf( fp, "[0x%x]\n", *pFramePtr ); + } + + fflush( fp ); + fclose( fp ); + } +} + +#endif /* defined LINUX */ + +#if defined( MACOSX ) + +#include <dlfcn.h> +#include <stdio.h> +#include "backtrace.h" + +typedef unsigned ptrdiff_t; + +/* glib backtrace is only available on MacOsX 10.5 or higher + so we do it on our own */ + +int backtrace( void **buffer, int max_frames ) +{ + void **frame = (void **)__builtin_frame_address(0); + void **bp = ( void **)(*frame); + void *ip = frame[1]; + int i; + + for ( i = 0; bp && ip && i < max_frames; i++ ) + { + *(buffer++) = ip; + + ip = bp[1]; + bp = (void**)(bp[0]); + } + + return i; +} + + +void backtrace_symbols_fd( void **buffer, int size, int fd ) +{ + FILE *fp = fdopen( fd, "w" ); + + if ( fp ) + { + void **pFramePtr; + + for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- ) + { + Dl_info dli; + ptrdiff_t offset; + + if ( 0 != dladdr( *pFramePtr, &dli ) ) + { + if ( dli.dli_fname && dli.dli_fbase ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase; + fprintf( fp, "%s+0x%x", dli.dli_fname, offset ); + } + if ( dli.dli_sname && dli.dli_saddr ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr; + fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset ); + } + } + fprintf( fp, "[0x%x]\n", (unsigned int)*pFramePtr ); + } + + fflush( fp ); + fclose( fp ); + } +} + +#endif /* defined MACOSX */ diff --git a/sal/osl/unx/backtrace.h b/sal/osl/unx/backtrace.h new file mode 100755 index 000000000000..1ca2ae84c4a0 --- /dev/null +++ b/sal/osl/unx/backtrace.h @@ -0,0 +1,99 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#if defined (SOLARIS) || (FREEBSD) + +#ifdef __cplusplus +extern "C" { +#endif + +/* backtrace function with same behaviour as defined in GNU libc */ + +int backtrace( void **buffer, int max_frames ); + +void backtrace_symbols_fd( void **buffer, int size, int fd ); + +/* no frame.h on FreeBSD */ +#if defined FREEBSD +struct frame { + long arg0[8]; + long arg1[6]; + struct frame *fr_savfp; + long fr_savpc; +}; +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined SOLARIS || FREEBSD */ + +#if defined (LINUX) && defined (SPARC) +#ifdef __cplusplus +extern "C" { +#endif + +/* backtrace function with same behaviour as defined in GNU libc */ + +int backtrace( void **buffer, int max_frames ); + +void backtrace_symbols_fd( void **buffer, int size, int fd ); + +/* no frame.h on linux sparc */ +struct frame { + long arg0[8]; + long arg1[6]; + struct frame *fr_savfp; + long fr_savpc; +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined LINUX && SPARC */ + +#if defined (MACOSX) + +#ifdef __cplusplus +extern "C" { +#endif + +/* backtrace function with same behaviour as defined in GNU libc */ + +int backtrace( void **buffer, int max_frames ); + +void backtrace_symbols_fd( void **buffer, int size, int fd ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined MACOSX */ diff --git a/sal/osl/unx/conditn.c b/sal/osl/unx/conditn.c new file mode 100644 index 000000000000..ea701d221e55 --- /dev/null +++ b/sal/osl/unx/conditn.c @@ -0,0 +1,350 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" +#include <sal/types.h> + +#include <osl/conditn.h> +#include <osl/diagnose.h> +#include <osl/time.h> + + +typedef struct _oslConditionImpl +{ + pthread_cond_t m_Condition; + pthread_mutex_t m_Lock; + sal_Bool m_State; +} oslConditionImpl; + + +/*****************************************************************************/ +/* osl_createCondition */ +/*****************************************************************************/ +oslCondition SAL_CALL osl_createCondition() +{ + oslConditionImpl* pCond; + int nRet=0; + + pCond = (oslConditionImpl*) malloc(sizeof(oslConditionImpl)); + + OSL_ASSERT(pCond); + + if ( pCond == 0 ) + { + return 0; + } + + pCond->m_State = sal_False; + + /* init condition variable with default attr. (PTHREAD_PROCESS_PRIVAT) */ + nRet = pthread_cond_init(&pCond->m_Condition, PTHREAD_CONDATTR_DEFAULT); + if ( nRet != 0 ) + { + OSL_TRACE("osl_createCondition : condition init failed. Errno: %d; '%s'\n", + nRet, strerror(nRet)); + + free(pCond); + return 0; + } + + nRet = pthread_mutex_init(&pCond->m_Lock, PTHREAD_MUTEXATTR_DEFAULT); + if ( nRet != 0 ) + { + OSL_TRACE("osl_createCondition : mutex init failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + + nRet = pthread_cond_destroy(&pCond->m_Condition); + if ( nRet != 0 ) + { + OSL_TRACE("osl_createCondition : destroy condition failed. Errno: %d; '%s'\n", + nRet, strerror(nRet)); + } + + free(pCond); + pCond = 0; + } + + return (oslCondition)pCond; +} + +/*****************************************************************************/ +/* osl_destroyCondition */ +/*****************************************************************************/ +void SAL_CALL osl_destroyCondition(oslCondition Condition) +{ + oslConditionImpl* pCond; + int nRet = 0; + + if ( Condition ) + { + pCond = (oslConditionImpl*)Condition; + + nRet = pthread_cond_destroy(&pCond->m_Condition); + if ( nRet != 0 ) + { + OSL_TRACE("osl_destroyCondition : destroy condition failed. Errno: %d; '%s'\n", + nRet, strerror(nRet)); + } + nRet = pthread_mutex_destroy(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_destroyCondition : destroy mutex failed. Errno: %d; '%s'\n", + nRet, strerror(nRet)); + } + + free(Condition); + } + + return; +} + +/*****************************************************************************/ +/* osl_setCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setCondition(oslCondition Condition) +{ + oslConditionImpl* pCond; + int nRet=0; + + OSL_ASSERT(Condition); + pCond = (oslConditionImpl*)Condition; + + if ( pCond == 0 ) + { + return sal_False; + } + + nRet = pthread_mutex_lock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_setCondition : mutex lock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + pCond->m_State = sal_True; + nRet = pthread_cond_broadcast(&pCond->m_Condition); + if ( nRet != 0 ) + { + OSL_TRACE("osl_setCondition : condition broadcast failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_setCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + return sal_True; + +} + +/*****************************************************************************/ +/* osl_resetCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_resetCondition(oslCondition Condition) +{ + oslConditionImpl* pCond; + int nRet=0; + + OSL_ASSERT(Condition); + + pCond = (oslConditionImpl*)Condition; + + if ( pCond == 0 ) + { + return sal_False; + } + + nRet = pthread_mutex_lock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_resetCondition : mutex lock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + pCond->m_State = sal_False; + + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_resetCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + return sal_True; +} + +/*****************************************************************************/ +/* osl_waitCondition */ +/*****************************************************************************/ +oslConditionResult SAL_CALL osl_waitCondition(oslCondition Condition, const TimeValue* pTimeout) +{ + oslConditionImpl* pCond; + int nRet=0; + oslConditionResult Result = osl_cond_result_ok; + + OSL_ASSERT(Condition); + pCond = (oslConditionImpl*)Condition; + + if ( pCond == 0 ) + { + return osl_cond_result_error; + } + + nRet = pthread_mutex_lock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : mutex lock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return osl_cond_result_error; + } + + if ( pTimeout ) + { + if ( ! pCond->m_State ) + { + int ret; + struct timeval tp; + struct timespec to; + + gettimeofday(&tp, NULL); + + SET_TIMESPEC( to, tp.tv_sec + pTimeout->Seconds, + tp.tv_usec * 1000 + pTimeout->Nanosec ); + + /* spurious wake up prevention */ + do + { + ret = pthread_cond_timedwait(&pCond->m_Condition, &pCond->m_Lock, &to); + if ( ret != 0 ) + { + if ( ret == ETIME || ret == ETIMEDOUT ) + { + Result = osl_cond_result_timeout; + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if (nRet != 0) + { + OSL_TRACE("osl_waitCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + return Result; + } + else if ( ret != EINTR ) + { + Result = osl_cond_result_error; + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + return Result; + } +/* OSL_TRACE("EINTR\n");*/ + } + } + while ( !pCond->m_State ); + } + } + else + { + while ( !pCond->m_State ) + { + nRet = pthread_cond_wait(&pCond->m_Condition, &pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : condition wait failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + Result = osl_cond_result_error; + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + return Result; + } + } + } + + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + return Result; +} + +/*****************************************************************************/ +/* osl_checkCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_checkCondition(oslCondition Condition) +{ + sal_Bool State; + oslConditionImpl* pCond; + int nRet=0; + + OSL_ASSERT(Condition); + pCond = (oslConditionImpl*)Condition; + + if ( pCond == 0 ) + { + return sal_False; + } + + nRet = pthread_mutex_lock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_checkCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + State = pCond->m_State; + + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_checkCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + return State; +} + + diff --git a/sal/osl/unx/diagnose.c b/sal/osl/unx/diagnose.c new file mode 100644 index 000000000000..bb8cbca406bd --- /dev/null +++ b/sal/osl/unx/diagnose.c @@ -0,0 +1,332 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/diagnose.h" +#include "system.h" + + +#ifndef HAVE_DLFCN_H + +#if defined(LINUX) || defined(SOLARIS) +#define HAVE_DLFCN_H +#endif /* LINUX || SOLARIS */ + +#endif /* HAVE_DLFCN_H */ + + +#ifdef HAVE_DLFCN_H + +#ifndef INCLUDED_DLFCN_H +#include <dlfcn.h> +#define INCLUDED_DLFCN_H +#endif + +#endif /* HAVE_DLFCN_H */ +#include "osl/thread.h" + +#ifndef INCLUDED_PTHREAD_H +#include <pthread.h> +#define INCLUDED_PTHREAD_H +#endif + +#ifndef INCLUDED_STDDEF_H +#include <stddef.h> +#define INCLUDED_STDDEF_H +#endif + +/************************************************************************/ +/* Internal data structures and functions */ +/************************************************************************/ + +static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; + +typedef pfunc_osl_printDebugMessage oslDebugMessageFunc; +static oslDebugMessageFunc volatile g_pDebugMessageFunc = 0; + +typedef pfunc_osl_printDetailedDebugMessage oslDetailedDebugMessageFunc; +static oslDetailedDebugMessageFunc volatile g_pDetailedDebugMessageFunc = 0; + +static void osl_diagnose_backtrace_Impl ( + oslDebugMessageFunc f); + +#define OSL_DIAGNOSE_OUTPUTMESSAGE(f, s) \ +((f != 0) ? (*(f))((s)) : (void)fprintf(stderr, "%s", (s))) + +#if defined (LINUX) || defined (SOLARIS) +/************************************************************************/ +/* osl_diagnose_frame_Impl */ +/************************************************************************/ +static void osl_diagnose_frame_Impl ( + oslDebugMessageFunc f, + int depth, + void * pc) +{ + const char *fname = 0, *sname = 0; + void *fbase = 0, *saddr = 0; + ptrdiff_t offset; + char szMessage[1024]; + +#ifdef INCLUDED_DLFCN_H + Dl_info dli; + if (dladdr (pc, &dli) != 0) + { + fname = dli.dli_fname; + fbase = dli.dli_fbase; + sname = dli.dli_sname; + saddr = dli.dli_saddr; + } +#endif /* INCLUDED_DLFCN_H */ + + if (saddr) + offset = (ptrdiff_t)(pc) - (ptrdiff_t)(saddr); + else if (fbase) + offset = (ptrdiff_t)(pc) - (ptrdiff_t)(fbase); + else + offset = (ptrdiff_t)(pc); + + snprintf (szMessage, sizeof(szMessage), + "Backtrace: [%d] %s: %s+0x%" SAL_PRI_PTRDIFFT "x\n", + depth, + fname ? fname : "<unknown>", + sname ? sname : "???", + offset); + + OSL_DIAGNOSE_OUTPUTMESSAGE(f, szMessage); +} +#endif + +/************************************************************************/ +/* osl_diagnose_backtrace_Impl */ +/************************************************************************/ +#if defined(LINUX) + +#include <execinfo.h> + +#define FRAME_COUNT 64 +#define FRAME_OFFSET 1 + +static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) +{ + void * ppFrames[FRAME_COUNT]; + int i, n; + + n = backtrace (ppFrames, FRAME_COUNT); + for (i = FRAME_OFFSET; i < n; i++) + { + osl_diagnose_frame_Impl (f, (i - FRAME_OFFSET), ppFrames[i]); + } +} + +#elif defined(SOLARIS) + +#include <pthread.h> +#include <setjmp.h> +#include <sys/frame.h> + +#if defined(SPARC) + +#if defined IS_LP64 + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0x7ff + +#else + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0 + +#endif + +#elif defined(INTEL) + +#define FRAME_PTR_OFFSET 3 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0 + +#endif /* (SPARC || INTEL) */ + +static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) +{ + jmp_buf ctx; + long fpval; + struct frame * fp; + int i; + +#if defined(SPARC) + asm("ta 3"); +#endif /* SPARC */ + setjmp (ctx); + + fpval = ((long*)(ctx))[FRAME_PTR_OFFSET]; + fp = (struct frame*)((char*)(fpval) + STACK_BIAS); + + for (i = 0; (i < FRAME_OFFSET) && (fp != 0); i++) + fp = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); + + for (i = 0; (fp != 0) && (fp->fr_savpc != 0); i++) + { + struct frame * prev = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); + osl_diagnose_frame_Impl (f, i, (void*)(fp->fr_savpc)); + fp = (prev > fp) ? prev : 0; + } +} + +#else /* (LINUX || SOLARIS) */ + +static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) +{ + /* not yet implemented */ +} + +#endif /* (LINUX || SOLARIS) */ + +/************************************************************************/ +/* osl_assertFailedLine */ +/************************************************************************/ +sal_Bool SAL_CALL osl_assertFailedLine ( + const sal_Char* pszFileName, + sal_Int32 nLine, + const sal_Char* pszMessage) +{ + oslDebugMessageFunc f = g_pDebugMessageFunc; + char szMessage[1024]; + + /* If there's a callback for detailed messages, use it */ + if ( g_pDetailedDebugMessageFunc != NULL ) + { + g_pDetailedDebugMessageFunc( pszFileName, nLine, pszMessage ); + return sal_False; + } + + /* if SAL assertions are disabled in general, stop here */ + if ( getenv("DISABLE_SAL_DBGBOX") ) + return sal_False; + + /* format message into buffer */ + if (pszMessage != 0) + { + snprintf(szMessage, sizeof(szMessage), + "Error: File %s, Line %" SAL_PRIdINT32 ": %s\n", + pszFileName, nLine, pszMessage); + } + else + { + snprintf(szMessage, sizeof(szMessage), + "Error: File %s, Line %" SAL_PRIdINT32 "\n", + pszFileName, nLine); + } + + /* acquire lock to serialize output message(s) */ + pthread_mutex_lock(&g_mutex); + + /* output message buffer */ + OSL_DIAGNOSE_OUTPUTMESSAGE(f, szMessage); + + /* output backtrace */ + osl_diagnose_backtrace_Impl(f); + + /* release lock and leave, w/o calling osl_breakDebug() */ + pthread_mutex_unlock(&g_mutex); + return sal_False; +} + +/************************************************************************/ +/* osl_breakDebug */ +/************************************************************************/ +void SAL_CALL osl_breakDebug() +{ + exit(0); +} + +/************************************************************************/ +/* osl_reportError */ +/************************************************************************/ +sal_Int32 SAL_CALL osl_reportError ( + sal_uInt32 nType, + const sal_Char* pszMessage) +{ + (void) nType; /* unused */ + fputs(pszMessage, stderr); + return 0; +} + +/************************************************************************/ +/* osl_setDebugMessageFunc */ +/************************************************************************/ +oslDebugMessageFunc SAL_CALL osl_setDebugMessageFunc ( + oslDebugMessageFunc pNewFunc) +{ + oslDebugMessageFunc pOldFunc = g_pDebugMessageFunc; + g_pDebugMessageFunc = pNewFunc; + return pOldFunc; +} + +/************************************************************************/ +/* osl_setDetailedDebugMessageFunc */ +/************************************************************************/ +pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc ( + pfunc_osl_printDetailedDebugMessage pNewFunc) +{ + oslDetailedDebugMessageFunc pOldFunc = g_pDetailedDebugMessageFunc; + g_pDetailedDebugMessageFunc = pNewFunc; + return pOldFunc; +} + +/************************************************************************/ +/* osl_trace */ +/************************************************************************/ +/* comment this define to stop output thread identifier*/ +#define OSL_TRACE_THREAD 1 +void SAL_CALL osl_trace ( + const sal_Char* lpszFormat, ...) +{ + va_list args; + +#if defined(OSL_PROFILING) + fprintf(stderr, "Time: %06lu : ", osl_getGlobalTimer() ); +#else +#if defined(OSL_TRACE_THREAD) + fprintf( + stderr, "Thread: %6lu :", + SAL_INT_CAST(unsigned long, osl_getThreadIdentifier(NULL))); +#else + fprintf(stderr, "Trace Message: "); +#endif +#endif + + va_start(args, lpszFormat); + vfprintf(stderr, lpszFormat, args); + va_end(args); + + fprintf(stderr,"\n"); + fflush(stderr); +} + +/************************************************************************/ + diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx new file mode 100644 index 000000000000..cc0c041bc328 --- /dev/null +++ b/sal/osl/unx/file.cxx @@ -0,0 +1,1397 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "osl/file.hxx" + +#include "osl/diagnose.h" +#include "rtl/alloc.h" + +#include "system.h" +#include "file_error_transl.h" +#include "file_url.h" + +#include <algorithm> +#include <limits> + +#include <string.h> +#include <pthread.h> +#include <sys/mman.h> + +#if defined(MACOSX) + +#include <sys/param.h> +#include <sys/mount.h> +#define HAVE_O_EXLOCK + +// add MACOSX Time Value +#define TimeValue CFTimeValue +#include <CoreFoundation/CoreFoundation.h> +#undef TimeValue + +#endif /* MACOSX */ + +#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 + +/******************************************************************* + * + * FileHandle_Impl interface + * + ******************************************************************/ +struct FileHandle_Impl +{ + pthread_mutex_t m_mutex; + 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_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 uSize); + + 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 ( + off_t 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(); + }; + + /** Guard. + */ + class Guard + { + pthread_mutex_t * m_mutex; + + public: + explicit Guard(pthread_mutex_t * pMutex); + ~Guard(); + }; +}; + +/******************************************************************* + * + * FileHandle_Impl implementation + * + ******************************************************************/ + +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(); + if (size_t(-1) != pagesize) + { + 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::Guard::Guard(pthread_mutex_t * pMutex) + : m_mutex (pMutex) +{ + OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer."); + (void) pthread_mutex_lock (m_mutex); // ignoring EINVAL ... +} +FileHandle_Impl::Guard::~Guard() +{ + OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer."); + (void) pthread_mutex_unlock (m_mutex); +} + +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) +{ + (void) pthread_mutex_init(&m_mutex, 0); + rtl_string_newFromStr (&m_strFilePath, path); + Allocator::get().allocate (&m_buffer, &m_bufsiz); + if (0 != m_buffer) + 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) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ... +} + +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() +{ +#if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) + return sal::static_int_cast< size_t >(::getpagesize()); +#else /* POSIX */ + return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE)); +#endif /* xBSD || POSIX */ +} + +sal_uInt64 FileHandle_Impl::getPos() const +{ + return sal::static_int_cast< sal_uInt64 >(m_fileptr); +} + +oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos) +{ + OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd, getPos(), uPos); + m_fileptr = sal::static_int_cast< off_t >(uPos); + return osl_File_E_None; +} + +sal_uInt64 FileHandle_Impl::getSize() const +{ + off_t const bufend = std::max((off_t)(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 defined(LINUX) || defined(SOLARIS) + + ssize_t nBytes = ::pread (m_fd, pBuffer, nBytesRequested, nOffset); + if ((-1 == nBytes) && (EOVERFLOW == errno)) + { + /* Some 'pread()'s fail with EOVERFLOW when reading at (or past) + * end-of-file, different from 'lseek() + read()' behaviour. + * Returning '0 bytes read' and 'osl_File_E_None' instead. + */ + nBytes = 0; + } + if (-1 == nBytes) + return oslTranslateFileError (OSL_FET_ERROR, errno); + +#else /* !(LINUX || SOLARIS) */ + + 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; + +#endif /* !(LINUX || SOLARIS) */ + + 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 defined(LINUX) || defined(SOLARIS) + + ssize_t nBytes = ::pwrite (m_fd, pBuffer, nBytesToWrite, nOffset); + if (-1 == nBytes) + return oslTranslateFileError (OSL_FET_ERROR, errno); + +#else /* !(LINUX || SOLARIS) */ + + 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; + +#endif /* !(LINUX || SOLARIS) */ + + 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); + m_bufptr = -1, m_buflen = 0; + + 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); + m_bufptr = -1, m_buflen = 0; + + 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 ( + off_t nOffset, + sal_Sequence ** ppSequence, + sal_uInt64 * pBytesRead) +{ + oslFileError result = osl_File_E_None; + + off_t 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 = 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 = 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 = uDone; + } + + bufpos = 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); +} + +/**************************************************************************** + * 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, 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; + + (void) pthread_mutex_lock (&(pImpl->m_mutex)); + + /* 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); + } + + (void) pthread_mutex_unlock (&(pImpl->m_mutex)); + 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; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + + OSL_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); + + void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset); + 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; + } + } + } + if (uFlags & osl_File_MapFlag_WillNeed) + { + // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable + // effect of not returning until the data has actually been paged in, so + // that its net effect would typically be to slow down the process + // (which could start processing at the beginning of the data while the + // OS simultaneously pages in the rest); on other platforms, it remains + // to be evaluated whether madvise or equivalent is available and + // actually useful: +#if defined MACOSX + int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED); + if (e != 0) + { + OSL_TRACE( + "posix_madvise(..., POSIX_MADV_WILLNEED) failed with %d", e); + } +#elif defined SOLARIS + if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0) + { + OSL_TRACE("madvise(..., MADV_WILLNEED) failed with %d", errno); + } +#endif + } + 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; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + 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; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + 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; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + 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 + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + 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 + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + 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; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *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; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *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); + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + 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; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *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); +} diff --git a/sal/osl/unx/file_error_transl.cxx b/sal/osl/unx/file_error_transl.cxx new file mode 100644 index 000000000000..3de829afc391 --- /dev/null +++ b/sal/osl/unx/file_error_transl.cxx @@ -0,0 +1,255 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + + #ifndef _ERRNO_H + #include <errno.h> + #endif + + #ifndef _FILE_ERROR_TRANSL_H_ + #include "file_error_transl.h" + #endif + + #ifndef _OSL_DIAGNOSE_H_ + #include <osl/diagnose.h> + #endif + + +/******************************************** + * oslTranslateFileError + *******************************************/ + +oslFileError oslTranslateFileError(sal_Bool bIsError, int Errno) +{ + oslFileError osl_error = osl_File_E_invalidError; + + OSL_ENSURE((bIsError && (0 != Errno)) || (!bIsError && (0 == Errno)), "oslTranslateFileError strange input combination!"); + + /* Have a look at file_error_transl.h for + the reason that we do this here */ + if (bIsError && (0 == Errno)) + return osl_error; + + switch(Errno) + { + case 0: + osl_error = osl_File_E_None; + break; + + case EPERM: + osl_error = osl_File_E_PERM; + break; + + case ENOENT: + osl_error = osl_File_E_NOENT; + break; + + case ESRCH: + osl_error = osl_File_E_SRCH; + break; + + case EINTR: + osl_error = osl_File_E_INTR; + break; + + case EIO: + osl_error = osl_File_E_IO; + break; + + case ENXIO: + osl_error = osl_File_E_IO; + break; + + case E2BIG: + osl_error = osl_File_E_2BIG; + break; + + case ENOEXEC: + osl_error = osl_File_E_NOEXEC; + break; + + case EBADF: + osl_error = osl_File_E_BADF; + break; + + case ECHILD: + osl_error = osl_File_E_CHILD; + break; + + case EAGAIN: + osl_error = osl_File_E_AGAIN; + break; + + case ENOMEM: + osl_error = osl_File_E_NOMEM; + break; + + case EACCES: + osl_error = osl_File_E_ACCES; + break; + + case EFAULT: + osl_error = osl_File_E_FAULT; + break; + + case EBUSY: + osl_error = osl_File_E_BUSY; + break; + + case EEXIST: + osl_error = osl_File_E_EXIST; + break; + + case EXDEV: + osl_error = osl_File_E_XDEV; + break; + + case ENODEV: + osl_error = osl_File_E_NODEV; + break; + + case ENOTDIR: + osl_error = osl_File_E_NOTDIR; + break; + + case EISDIR: + osl_error = osl_File_E_ISDIR; + break; + + case EINVAL: + osl_error = osl_File_E_INVAL; + break; + + case ENFILE: + osl_error = osl_File_E_NFILE; + break; + + case EMFILE: + osl_error = osl_File_E_MFILE; + break; + + case ENOTTY: + osl_error = osl_File_E_NOTTY; + break; + + case EFBIG: + osl_error = osl_File_E_FBIG; + break; + + case ENOSPC: + osl_error = osl_File_E_NOSPC; + break; + + case ESPIPE: + osl_error = osl_File_E_SPIPE; + break; + + case EROFS: + osl_error = osl_File_E_ROFS; + break; + + case EMLINK: + osl_error = osl_File_E_MLINK; + break; + + case EPIPE: + osl_error = osl_File_E_PIPE; + break; + + case EDOM: + osl_error = osl_File_E_DOM; + break; + + case ERANGE: + osl_error = osl_File_E_RANGE; + break; + + case EDEADLK: + osl_error = osl_File_E_DEADLK; + break; + + case ENAMETOOLONG: + osl_error = osl_File_E_NAMETOOLONG; + break; + + case ENOLCK: + osl_error = osl_File_E_NOLCK; + break; + + case ENOSYS: + osl_error = osl_File_E_NOSYS; + break; + + case ENOTEMPTY: + osl_error = osl_File_E_NOTEMPTY; + break; + + case ELOOP: + osl_error = osl_File_E_LOOP; + break; + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) + case EILSEQ: + osl_error = osl_File_E_ILSEQ; + break; +#endif /* MACOSX */ + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) + case ENOLINK: + osl_error = osl_File_E_NOLINK; + break; +#endif /* MACOSX */ + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) + case EMULTIHOP: + osl_error = osl_File_E_MULTIHOP; + break; +#endif /* MACOSX */ + + case EUSERS: + osl_error = osl_File_E_USERS; + break; + + case EOVERFLOW: + osl_error = osl_File_E_OVERFLOW; + break; + + case ETIMEDOUT: + osl_error = osl_File_E_TIMEDOUT; + break; + + default: + /* FIXME translateFileError: is this alright? Or add a new one: osl_File_E_Unknown? */ + osl_error = osl_File_E_invalidError; + break; + } + + return osl_error; +} + diff --git a/sal/osl/unx/file_error_transl.h b/sal/osl/unx/file_error_transl.h new file mode 100644 index 000000000000..59d7b1d9faec --- /dev/null +++ b/sal/osl/unx/file_error_transl.h @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _FILE_ERROR_TRANSL_H_ +#define _FILE_ERROR_TRANSL_H_ + +#include <osl/file.h> +#include <sal/types.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************* + oslTranslateFileError + Translate errno's to osl file errors + + @param bIsError [in] specifies if nErrno + should be interpreted as error, + some libc functions signaling an error + but errno is nevertheless 0 in this + case the function should at least + return osl_File_E_Unknown but in no + case osl_File_E_None! + + @param nErrno [in] the errno if errno is 0 + and bIsError is true the function + returns osl_File_E_Unknown + + @returns the osl error code appropriate to + the errno + + *********************************************/ + +#define OSL_FET_SUCCESS sal_False +#define OSL_FET_ERROR sal_True + +oslFileError oslTranslateFileError(sal_Bool bIsError, int Errno); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sal/osl/unx/file_impl.hxx b/sal/osl/unx/file_impl.hxx new file mode 100644 index 000000000000..5dee69f29b2e --- /dev/null +++ b/sal/osl/unx/file_impl.hxx @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_FILE_IMPL_HXX +#define INCLUDED_FILE_IMPL_HXX + +#include "osl/file.h" +#include <stddef.h> + +struct DirectoryItem_Impl +{ + sal_Int32 m_RefCount; + + rtl_uString * m_ustrFilePath; /* holds native file name */ + unsigned char m_DType; + + explicit DirectoryItem_Impl( + rtl_uString * ustrFilePath, unsigned char DType = 0); + ~DirectoryItem_Impl(); + + static void * operator new(size_t n); + static void operator delete (void * p, size_t); + + void acquire(); /* @see osl_acquireDirectoryItem() */ + void release(); /* @see osl_releaseDirectoryItem() */ + + oslFileType getFileType() const; +}; + +#endif /* INCLUDED_FILE_IMPL_HXX */ diff --git a/sal/osl/unx/file_misc.cxx b/sal/osl/unx/file_misc.cxx new file mode 100644 index 000000000000..331b91cb1626 --- /dev/null +++ b/sal/osl/unx/file_misc.cxx @@ -0,0 +1,1101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/file.hxx" + +#include "osl/diagnose.h" +#include "osl/thread.h" +#include <osl/signal.h> +#include "rtl/alloc.h" + +#include "system.h" +#include "file_impl.hxx" +#include "file_error_transl.h" +#include "file_path_helper.hxx" +#include "file_url.h" +#include "uunxapi.hxx" + +#include <sys/types.h> +#include <errno.h> +#include <dirent.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include <algorithm> + +/************************************************************************ + * ToDo + * + * - Fix: check for corresponding struct sizes in exported functions + * - check size/use of oslDirectory + * - check size/use of oslDirectoryItem + ***********************************************************************/ +/****************************************************************************** + * + * Data Type Definition + * + ******************************************************************************/ + +typedef struct +{ + rtl_uString* ustrPath; /* holds native directory path */ + DIR* pDirStruct; +} oslDirectoryImpl; + +#if 0 +/* FIXME: reintroducing this may save some extra bytes per Item */ +typedef struct +{ + rtl_uString* ustrFileName; /* holds native file name */ + rtl_uString* ustrDirPath; /* holds native dir path */ + sal_uInt32 RefCount; +} oslDirectoryItemImpl; +#endif + +DirectoryItem_Impl::DirectoryItem_Impl( + rtl_uString * ustrFilePath, unsigned char DType) + : m_RefCount (1), + m_ustrFilePath (ustrFilePath), + m_DType (DType) +{ + if (m_ustrFilePath != 0) + rtl_uString_acquire(m_ustrFilePath); +} +DirectoryItem_Impl::~DirectoryItem_Impl() +{ + if (m_ustrFilePath != 0) + rtl_uString_release(m_ustrFilePath); +} + +void * DirectoryItem_Impl::operator new(size_t n) +{ + return rtl_allocateMemory(n); +} +void DirectoryItem_Impl::operator delete(void * p, size_t) +{ + rtl_freeMemory(p); +} + +void DirectoryItem_Impl::acquire() +{ + ++m_RefCount; +} +void DirectoryItem_Impl::release() +{ + if (0 == --m_RefCount) + delete this; +} + +oslFileType DirectoryItem_Impl::getFileType() const +{ + switch (m_DType) + { +#ifdef _DIRENT_HAVE_D_TYPE + case DT_LNK: + return osl_File_Type_Link; + case DT_DIR: + return osl_File_Type_Directory; + case DT_REG: + return osl_File_Type_Regular; + case DT_FIFO: + return osl_File_Type_Fifo; + case DT_SOCK: + return osl_File_Type_Socket; + case DT_CHR: + case DT_BLK: + return osl_File_Type_Special; +#endif /* _DIRENT_HAVE_D_TYPE */ + default: + break; + } + return osl_File_Type_Unknown; +} + +/****************************************************************************** + * + * C-String Function Declarations + * + *****************************************************************************/ + +static oslFileError osl_psz_createDirectory(const sal_Char* pszPath); +static oslFileError osl_psz_removeDirectory(const sal_Char* pszPath); + +/******************************************************************* + * osl_openDirectory + ******************************************************************/ + +oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirectory* pDirectory) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError eRet; + + char path[PATH_MAX]; + + if ((0 == ustrDirectoryURL) || (0 == ustrDirectoryURL->length) || (0 == pDirectory)) + return osl_File_E_INVAL; + + /* 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 ) +#ifdef MACOSX + && macxp_resolveAlias( path, PATH_MAX ) == 0 +#endif /* MACOSX */ + ) + { + /* open directory */ + DIR *pdir = opendir( path ); + + if( pdir ) + { + /* create and initialize impl structure */ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) ); + + if( pDirImpl ) + { + pDirImpl->pDirStruct = pdir; + pDirImpl->ustrPath = ustrSystemPath; + + *pDirectory = (oslDirectory) pDirImpl; + return osl_File_E_None; + } + else + { + errno = ENOMEM; + closedir( pdir ); + } + } + else + { +#ifdef DEBUG_OSL_FILE + perror ("osl_openDirectory"); fprintf (stderr, path); +#endif + } + } + + rtl_uString_release( ustrSystemPath ); + + return oslTranslateFileError(OSL_FET_ERROR, errno); +} + +/****************************************************************************/ +/* osl_closeDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory ) +{ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) Directory; + oslFileError err = osl_File_E_None; + + OSL_ASSERT( Directory ); + + if( NULL == pDirImpl ) + return osl_File_E_INVAL; + + /* close directory */ + if( closedir( pDirImpl->pDirStruct ) ) + { + err = oslTranslateFileError(OSL_FET_ERROR, errno); + } + + /* cleanup members */ + rtl_uString_release( pDirImpl->ustrPath ); + + rtl_freeMemory( pDirImpl ); + + return err; +} + +/********************************************** + * 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_getNextDirectoryItem + ***************************************************************************/ + +oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirectoryItem* pItem, sal_uInt32 /*uHint*/) +{ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*)Directory; + 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; + + pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, sal_True); + + if (NULL == pEntry) + return osl_File_E_NOENT; + + +#if defined(MACOSX) + + // convert decomposed filename to precomposed unicode + char composed_name[BUFSIZ]; + CFMutableStringRef strRef = CFStringCreateMutable (NULL, 0 ); + CFStringAppendCString( strRef, pEntry->d_name, kCFStringEncodingUTF8 ); //UTF8 is default on Mac OSX + CFStringNormalize( strRef, kCFStringNormalizationFormC ); + CFStringGetCString( strRef, composed_name, BUFSIZ, kCFStringEncodingUTF8 ); + CFRelease( strRef ); + rtl_string2UString( &ustrFileName, composed_name, strlen( composed_name), + osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + +#else // not MACOSX + /* 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); + +#endif + + osl_systemPathMakeAbsolutePath(pDirImpl->ustrPath, ustrFileName, &ustrFilePath); + rtl_uString_release( ustrFileName ); + + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(*pItem); + if (0 != pImpl) + { + pImpl->release(), pImpl = 0; + } +#ifdef _DIRENT_HAVE_D_TYPE + pImpl = new DirectoryItem_Impl(ustrFilePath, pEntry->d_type); +#else + pImpl = new DirectoryItem_Impl(ustrFilePath); +#endif /* _DIRENT_HAVE_D_TYPE */ + *pItem = pImpl; + rtl_uString_release( ustrFilePath ); + + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_getDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getDirectoryItem( rtl_uString* ustrFileURL, oslDirectoryItem* pItem ) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError osl_error = osl_File_E_INVAL; + + OSL_ASSERT(ustrFileURL); + OSL_ASSERT(pItem); + + if (0 == ustrFileURL->length || NULL == pItem) + return osl_File_E_INVAL; + + osl_error = osl_getSystemPathFromFileURL_Ex(ustrFileURL, &ustrSystemPath, sal_False); + if (osl_File_E_None != osl_error) + return osl_error; + + osl_systemPathRemoveSeparator(ustrSystemPath); + + if (-1 == access_u(ustrSystemPath, F_OK)) + { + osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); + } + else + { + *pItem = new DirectoryItem_Impl(ustrSystemPath); + } + rtl_uString_release(ustrSystemPath); + + return osl_error; +} + + +/****************************************************************************/ +/* osl_acquireDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item ) +{ + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item); + if (0 == pImpl) + return osl_File_E_INVAL; + + pImpl->acquire(); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_releaseDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item ) +{ + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item); + if (0 == pImpl) + return osl_File_E_INVAL; + + pImpl->release(); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_createDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_createDirectory( rtl_uString* ustrDirectoryURL ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrDirectoryURL ); + + /* convert directory url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_createDirectory( path ); +} + +/****************************************************************************/ +/* osl_removeDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_removeDirectory( rtl_uString* ustrDirectoryURL ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrDirectoryURL ); + + /* convert directory url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_removeDirectory( path ); +} + +/***************************************** + * osl_psz_createDirectory + ****************************************/ + +static oslFileError osl_psz_createDirectory( const sal_Char* pszPath ) +{ + int nRet=0; + int mode = S_IRWXU | S_IRWXG | S_IRWXO; + + nRet = mkdir(pszPath,mode); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_removeDirectory + ****************************************/ + +static oslFileError osl_psz_removeDirectory( const sal_Char* pszPath ) +{ + int nRet=0; + + nRet = rmdir(pszPath); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_createDirectoryPath */ +/****************************************************************************/ + +static int path_make_parent(sal_Unicode* path) +{ + int i = rtl_ustr_lastIndexOfChar(path, '/'); + + if (i > 0) + { + *(path + i) = 0; + return i; + } + else + return 0; +} + +static 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; +} + +static 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); +} + +/****************************************************************************** + * + * C-String Function Declarations + * + *****************************************************************************/ + +static oslFileError osl_psz_removeFile(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 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); + +/****************************************************************************/ +/* osl_moveFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_moveFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL ) +{ + char srcPath[PATH_MAX]; + char destPath[PATH_MAX]; + oslFileError eRet; + + 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; + +#ifdef MACOSX + if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return oslDoMoveFile( srcPath, destPath ); +} + +/****************************************************************************/ +/* osl_copyFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_copyFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL ) +{ + char srcPath[PATH_MAX]; + char destPath[PATH_MAX]; + oslFileError eRet; + + 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; + +#ifdef MACOSX + if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_copyFile( srcPath, destPath ); +} + +/****************************************************************************/ +/* osl_removeFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_removeFile( rtl_uString* ustrFileURL ) +{ + 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; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_removeFile( path ); +} + +/****************************************************************************** + * + * Utility Functions + * + *****************************************************************************/ + +/***************************************** + * oslDoMoveFile + ****************************************/ + +static oslFileError oslDoMoveFile( const sal_Char* pszPath, const sal_Char* pszDestPath) +{ + oslFileError tErr=osl_File_E_invalidError; + + tErr = osl_psz_moveFile(pszPath,pszDestPath); + if ( tErr == osl_File_E_None ) + { + return tErr; + } + + if ( tErr != osl_File_E_XDEV ) + { + return tErr; + } + + tErr=osl_psz_copyFile(pszPath,pszDestPath); + + if ( tErr != osl_File_E_None ) + { + oslFileError tErrRemove; + tErrRemove=osl_psz_removeFile(pszDestPath); + return tErr; + } + + tErr=osl_psz_removeFile(pszPath); + + return tErr; +} + +/***************************************** + * osl_psz_removeFile + ****************************************/ +static oslFileError osl_psz_removeFile( const sal_Char* pszPath ) +{ + int nRet=0; + struct stat aStat; + + nRet = lstat(pszPath,&aStat); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + if ( S_ISDIR(aStat.st_mode) ) + { + return osl_File_E_ISDIR; + } + + nRet = unlink(pszPath); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_moveFile + ****************************************/ + +static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath) +{ + + int nRet = 0; + + nRet = rename(pszPath,pszDestPath); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_copyFile + ****************************************/ + +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; +} + + +/****************************************************************************** + * + * Utility Functions + * + *****************************************************************************/ + +/***************************************** + * oslDoCopy + ****************************************/ + +#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; + + SourceFileFD=open(pszSourceFileName,O_RDONLY); + if ( SourceFileFD < 0 ) + { + nRet=errno; + return nRet; + } + + DestFileFD=open(pszDestFileName, O_WRONLY | O_CREAT, 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; + } + + // read and lseek are used to check the possibility to access the data + // not a nice solution, but it allows to avoid a crash in case it is an opened samba file + // generally, reading of one byte should not affect the performance + char nCh; + if ( 1 != read( SourceFileFD, &nCh, 1 ) + || -1 == lseek( SourceFileFD, 0, SEEK_SET ) ) + { + nRet = errno; + close( SourceFileFD ); + close( DestFileFD ); + return nRet; + } + + size_t nWritten = 0; + size_t nRemains = nSourceSize; + + /* mmap file -- open dest file -- write -- fsync it at the end */ + void* pSourceFile = mmap( 0, nSourceSize, PROT_READ, MAP_SHARED, SourceFileFD, 0 ); + if ( pSourceFile != MAP_FAILED ) + { + nWritten = write( DestFileFD, pSourceFile, nSourceSize ); + nRemains -= nWritten; + munmap( (char*)pSourceFile, nSourceSize ); + } + + if ( nRemains ) + { + /* mmap has problems, try the direct streaming */ + char pBuffer[32000]; + size_t nRead = 0; + + nRemains = nSourceSize; + + if ( -1 != lseek( SourceFileFD, 0, SEEK_SET ) + && -1 != lseek( DestFileFD, 0, SEEK_SET ) ) + { + do + { + nRead = 0; + nWritten = 0; + + size_t nToRead = std::min( (size_t)32000, nRemains ); + nRead = read( SourceFileFD, pBuffer, nToRead ); + if ( (size_t)-1 != nRead ) + nWritten = write( DestFileFD, pBuffer, nRead ); + + if ( (size_t)-1 != nWritten ) + nRemains -= nWritten; + } + while( nRemains && (size_t)-1 != nRead && nRead == nWritten ); + } + } + + if ( nRemains ) + { + if ( errno ) + nRet = errno; + else + nRet = ENOSPC; + } + + close( SourceFileFD ); + if ( close( DestFileFD ) == -1 && nRet == 0 ) + nRet = errno; + + return nRet; +} + diff --git a/sal/osl/unx/file_path_helper.cxx b/sal/osl/unx/file_path_helper.cxx new file mode 100644 index 000000000000..04fdd13e7c15 --- /dev/null +++ b/sal/osl/unx/file_path_helper.cxx @@ -0,0 +1,350 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + + /******************************************* + Includes + ******************************************/ + + #ifndef _OSL_FILE_PATH_HELPER_H_ + #include "file_path_helper.h" + #endif + + #ifndef _OSL_FILE_PATH_HELPER_HXX_ + #include "file_path_helper.hxx" + #endif + + #ifndef _OSL_UUNXAPI_HXX_ + #include "uunxapi.hxx" + #endif + + #ifndef _OSL_DIAGNOSE_H_ + #include <osl/diagnose.h> + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + /******************************************* + Constants + ******************************************/ + + const sal_Unicode FPH_CHAR_PATH_SEPARATOR = (sal_Unicode)'/'; + const sal_Unicode FPH_CHAR_DOT = (sal_Unicode)'.'; + const sal_Unicode FPH_CHAR_COLON = (sal_Unicode)':'; + + inline const rtl::OUString FPH_PATH_SEPARATOR() + { return rtl::OUString::createFromAscii("/"); } + inline const rtl::OUString FPH_LOCAL_DIR_ENTRY() + { return rtl::OUString::createFromAscii("."); } + inline const rtl::OUString FPH_PARENT_DIR_ENTRY() + { return rtl::OUString::createFromAscii(".."); } + + /******************************************* + * osl_systemPathRemoveSeparator + ******************************************/ + + void SAL_CALL osl_systemPathRemoveSeparator(rtl_uString* pustrPath) + { + OSL_PRECOND(pustrPath, "osl_systemPathRemoveSeparator: Invalid parameter"); + + // maybe there are more than one separator at end + // so we run in a loop + while ((pustrPath->length > 1) && (FPH_CHAR_PATH_SEPARATOR == pustrPath->buffer[pustrPath->length - 1])) + { + pustrPath->length--; + pustrPath->buffer[pustrPath->length] = (sal_Unicode)'\0'; + } + + OSL_POSTCOND((0 == pustrPath->length) || (1 == pustrPath->length) || \ + (pustrPath->length > 1 && pustrPath->buffer[pustrPath->length - 1] != FPH_CHAR_PATH_SEPARATOR), \ + "osl_systemPathRemoveSeparator: Post condition failed"); + } + + /******************************************* + osl_systemPathEnsureSeparator + ******************************************/ + + void SAL_CALL osl_systemPathEnsureSeparator(rtl_uString** ppustrPath) + { + OSL_PRECOND(ppustrPath && (NULL != *ppustrPath), \ + "osl_systemPathEnsureSeparator: Invalid parameter"); + + rtl::OUString path(*ppustrPath); + sal_Int32 lp = path.getLength(); + sal_Int32 i = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR); + + if ((lp > 1 && i != (lp - 1)) || ((lp < 2) && i < 0)) + { + path += FPH_PATH_SEPARATOR(); + rtl_uString_assign(ppustrPath, path.pData); + } + + OSL_POSTCOND(path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR) == (path.getLength() - 1), \ + "osl_systemPathEnsureSeparator: Post condition failed"); + } + + /******************************************* + * osl_systemPathIsRelativePath + ******************************************/ + + sal_Bool SAL_CALL osl_systemPathIsRelativePath(const rtl_uString* pustrPath) + { + OSL_PRECOND(pustrPath, "osl_systemPathIsRelativePath: Invalid parameter"); + return ((0 == pustrPath->length) || (pustrPath->buffer[0] != FPH_CHAR_PATH_SEPARATOR)); + } + + /****************************************** + osl_systemPathMakeAbsolutePath + *****************************************/ + + void SAL_CALL osl_systemPathMakeAbsolutePath( + const rtl_uString* pustrBasePath, + const rtl_uString* pustrRelPath, + rtl_uString** ppustrAbsolutePath) +{ + rtl::OUString base(rtl_uString_getStr(const_cast<rtl_uString*>(pustrBasePath))); + rtl::OUString rel(const_cast<rtl_uString*>(pustrRelPath)); + + if (base.getLength() > 0) + osl_systemPathEnsureSeparator(&base.pData); + + base += rel; + + rtl_uString_acquire(base.pData); + *ppustrAbsolutePath = base.pData; +} + + + /******************************************* + osl_systemPathGetFileOrLastDirectoryPart + ******************************************/ + + void SAL_CALL osl_systemPathGetFileNameOrLastDirectoryPart( + const rtl_uString* pustrPath, + rtl_uString** ppustrFileNameOrLastDirPart) +{ + OSL_PRECOND(pustrPath && ppustrFileNameOrLastDirPart, \ + "osl_systemPathGetFileNameOrLastDirectoryPart: Invalid parameter"); + + rtl::OUString path(const_cast<rtl_uString*>(pustrPath)); + + osl_systemPathRemoveSeparator(path.pData); + + rtl::OUString last_part; + + if (path.getLength() > 1 || (1 == path.getLength() && *path.getStr() != FPH_CHAR_PATH_SEPARATOR)) + { + sal_Int32 idx_ps = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR); + idx_ps++; // always right to increment by one even if idx_ps == -1! + last_part = rtl::OUString(path.getStr() + idx_ps); + } + rtl_uString_assign(ppustrFileNameOrLastDirPart, last_part.pData); +} + + + /******************************************** + osl_systemPathIsHiddenFileOrDirectoryEntry + *********************************************/ + + sal_Bool SAL_CALL osl_systemPathIsHiddenFileOrDirectoryEntry( + const rtl_uString* pustrPath) +{ + OSL_PRECOND(pustrPath, "osl_systemPathIsHiddenFileOrDirectoryEntry: Invalid parameter"); + + sal_Bool is_hidden = sal_False; + + if (pustrPath->length > 0) + { + rtl::OUString fdp; + + osl_systemPathGetFileNameOrLastDirectoryPart(pustrPath, &fdp.pData); + + is_hidden = ((fdp.pData->length > 0) && (fdp.pData->buffer[0] == FPH_CHAR_DOT) && + !osl_systemPathIsLocalOrParentDirectoryEntry(fdp.pData)); + } + + return is_hidden; +} + + + /************************************************ + osl_systemPathIsLocalOrParentDirectoryEntry + ************************************************/ + +sal_Bool SAL_CALL osl_systemPathIsLocalOrParentDirectoryEntry( + const rtl_uString* pustrPath) +{ + OSL_PRECOND(pustrPath, "osl_systemPathIsLocalOrParentDirectoryEntry: Invalid parameter"); + + rtl::OUString dirent; + + osl_systemPathGetFileNameOrLastDirectoryPart(pustrPath, &dirent.pData); + + return ( + (dirent == FPH_LOCAL_DIR_ENTRY()) || + (dirent == FPH_PARENT_DIR_ENTRY()) + ); +} + +/*********************************************** + Simple iterator for a path list separated by + the specified character + **********************************************/ + +class path_list_iterator +{ +public: + + /****************************************** + constructor + + after construction get_current_item + returns the first path in list, no need + to call reset first + *****************************************/ + path_list_iterator(const rtl::OUString& path_list, sal_Unicode list_separator = FPH_CHAR_COLON) : + m_path_list(path_list), + m_end(m_path_list.getStr() + m_path_list.getLength() + 1), + m_separator(list_separator) + { + reset(); + } + + /****************************************** + reset the iterator + *****************************************/ + void reset() + { + m_path_segment_begin = m_path_segment_end = m_path_list.getStr(); + advance(); + } + + /****************************************** + move the iterator to the next position + *****************************************/ + void next() + { + OSL_PRECOND(!done(), "path_list_iterator: Already done!"); + + m_path_segment_begin = ++m_path_segment_end; + advance(); + } + + /****************************************** + check if done + *****************************************/ + bool done() const + { + return (m_path_segment_end >= m_end); + } + + /****************************************** + return the current item + *****************************************/ + rtl::OUString get_current_item() const + { + return rtl::OUString( + m_path_segment_begin, + (m_path_segment_end - m_path_segment_begin)); + } + +private: + + /****************************************** + move m_path_end to the next separator or + to the edn of the string + *****************************************/ + void advance() + { + while (!done() && *m_path_segment_end && (*m_path_segment_end != m_separator)) + ++m_path_segment_end; + + OSL_ASSERT(m_path_segment_end <= m_end); + } + +private: + rtl::OUString m_path_list; + const sal_Unicode* m_end; + const sal_Unicode m_separator; + const sal_Unicode* m_path_segment_begin; + const sal_Unicode* m_path_segment_end; + +// prevent copy and assignment +private: + /****************************************** + copy constructor + remember: do not simply copy m_path_begin + and m_path_end because they point to + the memory of other.m_path_list! + *****************************************/ + path_list_iterator(const path_list_iterator& other); + + /****************************************** + assignment operator + remember: do not simply copy m_path_begin + and m_path_end because they point to + the memory of other.m_path_list! + *****************************************/ + path_list_iterator& operator=(const path_list_iterator& other); +}; + + /************************************************ + osl_searchPath + ***********************************************/ + +sal_Bool SAL_CALL osl_searchPath( + const rtl_uString* pustrFilePath, + const rtl_uString* pustrSearchPathList, + rtl_uString** ppustrPathFound) +{ + OSL_PRECOND(pustrFilePath && pustrSearchPathList && ppustrPathFound, "osl_searchPath: Invalid parameter"); + + bool bfound = false; + rtl::OUString fp(const_cast<rtl_uString*>(pustrFilePath)); + rtl::OUString pl = rtl::OUString(const_cast<rtl_uString*>(pustrSearchPathList)); + path_list_iterator pli(pl); + + while (!pli.done()) + { + rtl::OUString p = pli.get_current_item(); + osl::systemPathEnsureSeparator(p); + p += fp; + + if (osl::access(p, F_OK) > -1) + { + bfound = true; + rtl_uString_assign(ppustrPathFound, p.pData); + break; + } + pli.next(); + } + return bfound; +} diff --git a/sal/osl/unx/file_path_helper.h b/sal/osl/unx/file_path_helper.h new file mode 100644 index 000000000000..c1e3908fa9f2 --- /dev/null +++ b/sal/osl/unx/file_path_helper.h @@ -0,0 +1,247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_FILE_PATH_HELPER_H_ + #define _OSL_FILE_PATH_HELPER_H_ + + + #ifndef _SAL_TYPES_H_ + #include <sal/types.h> + #endif + + #ifndef _RTL_USTRING_H_ + #include <rtl/ustring.h> + #endif + + + #ifdef __cplusplus + extern "C" + { + #endif + + + /******************************************* + osl_systemPathRemoveSeparator + Removes the last separator from the + given system path if any and if the path + is not the root path '/' + + @param ppustrPath [inout] a system path + if the path is not the root path + and the last character is a + path separator it will be cut off + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + void SAL_CALL osl_systemPathRemoveSeparator( + /*inout*/ rtl_uString* pustrPath); + + /******************************************* + osl_systemPathEnsureSeparator + Adds a trailing path separator to the + given system path if not already there + and if the path is not the root path '/' + + @param pustrPath [inout] a system path + if the path is not the root path + '/' and has no trailing separator + a separator will be added + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + void SAL_CALL osl_systemPathEnsureSeparator( + /*inout*/ rtl_uString** ppustrPath); + + /******************************************* + osl_systemPathIsRelativePath + Returns true if the given path is a + relative path and so starts not with '/' + + @param pustrPath [in] a system path + pustrPath must not be NULL + + @returns sal_True if the given path + doesn't start with a separator + else sal_False will be returned + + ******************************************/ + + sal_Bool SAL_CALL osl_systemPathIsRelativePath( + const rtl_uString* pustrPath); + + /****************************************** + osl_systemPathMakeAbsolutePath + Append a relative path to a base path + + @param pustrBasePath [in] a system + path that will be considered as + base path + pustrBasePath must not be NULL + + @param pustrRelPath [in] a system path + that will be considered as + relative path + pustrBasePath must not be NULL + + @param ppustrAbsolutePath [out] the + resulting path which is a + concatination of the base and + the relative path + if base path is empty the + resulting absolute path is the + relative path + if relative path is empty the + resulting absolute path is the + base path + if base and relative path are + empty the resulting absolute + path is also empty + ppustrAbsolutePath must not be + NULL and *ppustrAbsolutePath + must be 0 or point to a valid + rtl_uString + + *****************************************/ + + void SAL_CALL osl_systemPathMakeAbsolutePath( + const rtl_uString* pustrBasePath, + const rtl_uString* pustrRelPath, + rtl_uString** ppustrAbsolutePath); + + /***************************************** + osl_systemPathGetFileOrLastDirectoryPart + Returns the file or the directory part + of the given path + + @param pustrPath [in] a system path, + must not be NULL + + @param ppustrFileOrDirPart [out] on + return receives the last part + of the given directory or the + file name + if pustrPath is the root path + '/' an empty string will be + returned + if pustrPath has a trailing + '/' the last part before the + '/' will be returned else + the part after the last '/' + will be returned + + @returns nothing + + ****************************************/ + void SAL_CALL osl_systemPathGetFileNameOrLastDirectoryPart( + const rtl_uString* pustrPath, + rtl_uString** ppustrFileNameOrLastDirPart); + + + /******************************************** + osl_systemPathIsHiddenFileOrDirectoryEntry + Returns sal_True if the last part of + given system path is not '.' or '..' + alone and starts with a '.' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of + the given system path starts + with '.' or sal_False the last + part is '.' or '..' alone or + doesn't start with a dot + + *********************************************/ + + sal_Bool SAL_CALL osl_systemPathIsHiddenFileOrDirectoryEntry( + const rtl_uString* pustrPath); + + + /************************************************ + osl_systemPathIsLocalOrParentDirectoryEntry + Returns sal_True if the last part of the given + system path is the local directory entry '.' + or the parent directory entry '..' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of the + given system path is '.' or '..' + else sal_False + + ************************************************/ + + sal_Bool SAL_CALL osl_systemPathIsLocalOrParentDirectoryEntry( + const rtl_uString* pustrPath); + + + /************************************************ + osl_searchPath + Searches for a file name or path name in all + directories specified by a given path list. + Symbolic links in the resulting path will not be + resolved, it's up to the caller to do this. + + @param pustrFilePath [in] a file name or + directory name to search for, the name must + be provided as system path not as a file URL + + @param pustrSearchPathList [in] a ':' + separated list of paths in which to search for + the file or directory name + + @ppustrPathFound [out] on success receives the + complete path of the file or directory found + as a system path + + @returns sal_True if the specified file or + directory was found else sal_False + ***********************************************/ + + sal_Bool SAL_CALL osl_searchPath( + const rtl_uString* pustrFilePath, + const rtl_uString* pustrSearchPathList, + rtl_uString** ppustrPathFound); + + + #ifdef __cplusplus + } + #endif + + + #endif /* #ifndef _OSL_PATH_HELPER_H_ */ + diff --git a/sal/osl/unx/file_path_helper.hxx b/sal/osl/unx/file_path_helper.hxx new file mode 100644 index 000000000000..4b429b111799 --- /dev/null +++ b/sal/osl/unx/file_path_helper.hxx @@ -0,0 +1,247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_FILE_PATH_HELPER_HXX_ +#define _OSL_FILE_PATH_HELPER_HXX_ + + +#ifndef _OSL_FILE_PATH_HELPER_H_ +#include "file_path_helper.h" +#endif + +#include <rtl/ustring.hxx> + + +namespace osl +{ + + /******************************************* + systemPathRemoveSeparator + Removes the last separator from the + given system path if any and if the path + is not the root path '/' + + @param ppustrPath [inout] a system path + if the path is not the root path + and the last character is a + path separator it will be cut off + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + inline void systemPathRemoveSeparator(/*inout*/ rtl::OUString& Path) + { + osl_systemPathRemoveSeparator(Path.pData); + } + + /******************************************* + systemPathEnsureSeparator + Adds a trailing path separator to the + given system path if not already there + and if the path is not the root path '/' + + @param pustrPath [inout] a system path + if the path is not the root path + '/' and has no trailing separator + a separator will be added + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + inline void systemPathEnsureSeparator(/*inout*/ rtl::OUString& Path) + { + osl_systemPathEnsureSeparator(&Path.pData); + } + + /******************************************* + systemPathIsRelativePath + Returns true if the given path is a + relative path and so starts not with '/' + + @param pustrPath [in] a system path + pustrPath must not be NULL + + @returns sal_True if the given path + doesn't start with a separator + else sal_False will be returned + + ******************************************/ + + inline bool systemPathIsRelativePath(const rtl::OUString& Path) + { + return osl_systemPathIsRelativePath(Path.pData); + } + + /****************************************** + systemPathMakeAbsolutePath + Append a relative path to a base path + + @param pustrBasePath [in] a system + path that will be considered as + base path + pustrBasePath must not be NULL + + @param pustrRelPath [in] a system path + that will be considered as + relative path + pustrBasePath must not be NULL + + @param ppustrAbsolutePath [out] the + resulting path which is a + concatination of the base and + the relative path + if base path is empty the + resulting absolute path is the + relative path + if relative path is empty the + resulting absolute path is the + base path + if base and relative path are + empty the resulting absolute + path is also empty + ppustrAbsolutePath must not be + NULL and *ppustrAbsolutePath + must be 0 or point to a valid + rtl_uString + + *****************************************/ + + inline void systemPathMakeAbsolutePath( + const rtl::OUString& BasePath, + const rtl::OUString& RelPath, + rtl::OUString& AbsolutePath) + { + osl_systemPathMakeAbsolutePath( + BasePath.pData, RelPath.pData, &AbsolutePath.pData); + } + + /***************************************** + systemPathGetFileOrLastDirectoryPart + Returns the file or the directory part + of the given path + + @param pustrPath [in] a system path, + must not be NULL + + @param ppustrFileOrDirPart [out] on + return receives the last part + of the given directory or the + file name + if pustrPath is the root path + '/' an empty string will be + returned + if pustrPath has a trailing + '/' the last part before the + '/' will be returned else + the part after the last '/' + will be returned + + @returns nothing + + ****************************************/ + + inline void systemPathGetFileNameOrLastDirectoryPart( + const rtl::OUString& Path, + rtl::OUString& FileNameOrLastDirPart) + { + osl_systemPathGetFileNameOrLastDirectoryPart( + Path.pData, &FileNameOrLastDirPart.pData); + } + + + /******************************************** + systemPathIsHiddenFileOrDirectoryEntry + Returns sal_True if the last part of + given system path is not '.' or '..' + alone and starts with a '.' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of + the given system path starts + with '.' or sal_False the last + part is '.' or '..' alone or + doesn't start with a dot + + *********************************************/ + + inline bool systemPathIsHiddenFileOrDirectoryEntry( + const rtl::OUString& Path) + { + return osl_systemPathIsHiddenFileOrDirectoryEntry(Path.pData); + } + + + /************************************************ + systemPathIsLocalOrParentDirectoryEntry + Returns sal_True if the last part of the given + system path is the local directory entry '.' + or the parent directory entry '..' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of the + given system path is '.' or '..' + else sal_False + + ************************************************/ + + inline bool systemPathIsLocalOrParentDirectoryEntry( + const rtl::OUString& Path) + { + return osl_systemPathIsLocalOrParentDirectoryEntry(Path.pData); + } + + /************************************************ + searchPath + ***********************************************/ + + inline bool searchPath( + const rtl::OUString& ustrFilePath, + const rtl::OUString& ustrSearchPathList, + rtl::OUString& ustrPathFound) + { + return osl_searchPath( + ustrFilePath.pData, + ustrSearchPathList.pData, + &ustrPathFound.pData); + } + + + } // namespace osl + + + #endif /* #ifndef _OSL_PATH_HELPER_HXX_ */ + diff --git a/sal/osl/unx/file_stat.cxx b/sal/osl/unx/file_stat.cxx new file mode 100644 index 000000000000..df32fa105a50 --- /dev/null +++ b/sal/osl/unx/file_stat.cxx @@ -0,0 +1,492 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "osl/file.h" + +#include "system.h" +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <limits.h> +#include <unistd.h> + +#include "file_impl.hxx" +#include "file_error_transl.h" +#include "file_path_helper.hxx" +#include "file_url.h" +#include "uunxapi.hxx" + +namespace /* private */ +{ + + inline void set_file_type(const struct stat& file_stat, oslFileStatus* pStat) + { + /* links to directories state also to be a directory */ + if (S_ISLNK(file_stat.st_mode)) + pStat->eType = osl_File_Type_Link; + else if (S_ISDIR(file_stat.st_mode)) + pStat->eType = osl_File_Type_Directory; + else if (S_ISREG(file_stat.st_mode)) + pStat->eType = osl_File_Type_Regular; + else if (S_ISFIFO(file_stat.st_mode)) + pStat->eType = osl_File_Type_Fifo; + else if (S_ISSOCK(file_stat.st_mode)) + pStat->eType = osl_File_Type_Socket; + else if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode)) + pStat->eType = osl_File_Type_Special; + else + pStat->eType = osl_File_Type_Unknown; + + pStat->uValidFields |= osl_FileStatus_Mask_Type; + } + + inline void set_file_access_mask(const struct stat& file_stat, oslFileStatus* pStat) + { + // user permissions + if (S_IRUSR & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OwnRead; + + if (S_IWUSR & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OwnWrite; + + if (S_IXUSR & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OwnExe; + + // group permissions + if (S_IRGRP & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_GrpRead; + + if (S_IWGRP & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_GrpWrite; + + if (S_IXGRP & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_GrpExe; + + // others permissions + if (S_IROTH & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OthRead; + + if (S_IWOTH & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OthWrite; + + if (S_IXOTH & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OthExe; + + pStat->uValidFields |= osl_FileStatus_Mask_Attributes; + } + + inline void set_file_access_rights(const struct stat& file_stat, int S_IR, int S_IW, int S_IX, oslFileStatus* pStat) + { + /* we cannot really map osl_File_Attribute_ReadOnly to + the Unix access rights, it's a Windows only flag + that's why the following hack. We set osl_FileStatus_Mask_Attributes + but if there is no read access for a file we clear the flag + again to signal to the caller that there are no file attributes + to read because that's better than to give them incorrect one. + */ + pStat->uValidFields |= osl_FileStatus_Mask_Attributes; + + if ((0 == (S_IW & file_stat.st_mode)) && (S_IR & file_stat.st_mode)) + pStat->uAttributes |= osl_File_Attribute_ReadOnly; + + if (S_IX & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_Executable; + } + + /* a process may belong to up to NGROUPS_MAX groups, so when + checking group access rights, we have to check all belonging + groups */ + inline bool is_in_process_grouplist(const gid_t file_group) + { + // check primary process group + + if (getgid() == file_group) + return true; + + // check supplementary process groups + + gid_t grplist[NGROUPS_MAX]; + int grp_number = getgroups(NGROUPS_MAX, grplist); + + for (int i = 0; i < grp_number; i++) + { + if (grplist[i] == file_group) + return true; + } + return false; + } + + /* Currently we are determining the file access right based + on the real user ID not the effective user ID! + We don't use access(...) because access follows links which + may cause performance problems see #97133. + */ + inline void set_file_access_rights(const struct stat& file_stat, oslFileStatus* pStat) + { + if (getuid() == file_stat.st_uid) + { + set_file_access_rights(file_stat, S_IRUSR, S_IWUSR, S_IXUSR, pStat); + } + else if (is_in_process_grouplist(file_stat.st_gid)) + { + set_file_access_rights(file_stat, S_IRGRP, S_IWGRP, S_IXGRP, pStat); + } + else + { + set_file_access_rights(file_stat, S_IROTH, S_IWOTH, S_IXOTH, pStat); + } + } + + inline void set_file_hidden_status(const rtl::OUString& file_path, oslFileStatus* pStat) + { + pStat->uAttributes = osl::systemPathIsHiddenFileOrDirectoryEntry(file_path) ? osl_File_Attribute_Hidden : 0; + pStat->uValidFields |= osl_FileStatus_Mask_Attributes; + } + + /* the set_file_access_rights must be called after set_file_hidden_status(...) and + set_file_access_mask(...) because of the hack in set_file_access_rights(...) */ + inline void set_file_attributes( + const rtl::OUString& file_path, const struct stat& file_stat, const sal_uInt32 uFieldMask, oslFileStatus* pStat) + { + set_file_hidden_status(file_path, pStat); + set_file_access_mask(file_stat, pStat); + + // we set the file access rights only on demand + // because it's potentially expensive + if (uFieldMask & osl_FileStatus_Mask_Attributes) + set_file_access_rights(file_stat, pStat); + } + + inline void set_file_access_time(const struct stat& file_stat, oslFileStatus* pStat) + { + pStat->aAccessTime.Seconds = file_stat.st_atime; + pStat->aAccessTime.Nanosec = 0; + pStat->uValidFields |= osl_FileStatus_Mask_AccessTime; + } + + inline void set_file_modify_time(const struct stat& file_stat, oslFileStatus* pStat) + { + pStat->aModifyTime.Seconds = file_stat.st_mtime; + pStat->aModifyTime.Nanosec = 0; + pStat->uValidFields |= osl_FileStatus_Mask_ModifyTime; + } + + inline void set_file_size(const struct stat& file_stat, oslFileStatus* pStat) + { + if (S_ISREG(file_stat.st_mode)) + { + pStat->uFileSize = file_stat.st_size; + pStat->uValidFields |= osl_FileStatus_Mask_FileSize; + } + } + + /* we only need to call stat or lstat if one of the + following flags is set */ + inline bool is_stat_call_necessary(sal_uInt32 field_mask, oslFileType file_type = osl_File_Type_Unknown) + { + return ( + ((field_mask & osl_FileStatus_Mask_Type) && (file_type == osl_File_Type_Unknown)) || + (field_mask & osl_FileStatus_Mask_Attributes) || + (field_mask & osl_FileStatus_Mask_CreationTime) || + (field_mask & osl_FileStatus_Mask_AccessTime) || + (field_mask & osl_FileStatus_Mask_ModifyTime) || + (field_mask & osl_FileStatus_Mask_FileSize) || + (field_mask & osl_FileStatus_Mask_LinkTargetURL) || + (field_mask & osl_FileStatus_Mask_Validate)); + } + + inline oslFileError set_link_target_url(const rtl::OUString& file_path, oslFileStatus* pStat) + { + rtl::OUString link_target; + if (!osl::realpath(file_path, link_target)) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + oslFileError osl_error = osl_getFileURLFromSystemPath(link_target.pData, &pStat->ustrLinkTargetURL); + if (osl_error != osl_File_E_None) + return osl_error; + + pStat->uValidFields |= osl_FileStatus_Mask_LinkTargetURL; + return osl_File_E_None; + } + + inline oslFileError setup_osl_getFileStatus( + DirectoryItem_Impl * pImpl, oslFileStatus* pStat, rtl::OUString& file_path) + { + if ((NULL == pImpl) || (NULL == pStat)) + return osl_File_E_INVAL; + + file_path = rtl::OUString(pImpl->m_ustrFilePath); + OSL_ASSERT(file_path.getLength() > 0); + if (file_path.getLength() <= 0) + return osl_File_E_INVAL; + + pStat->uValidFields = 0; + return osl_File_E_None; + } + +} // end namespace private + + +/**************************************************************************** + * osl_getFileStatus + ****************************************************************************/ + +oslFileError SAL_CALL osl_getFileStatus(oslDirectoryItem Item, oslFileStatus* pStat, sal_uInt32 uFieldMask) +{ + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item); + + rtl::OUString file_path; + oslFileError osl_error = setup_osl_getFileStatus(pImpl, pStat, file_path); + if (osl_File_E_None != osl_error) + return osl_error; + +#if defined(__GNUC__) && (__GNUC__ < 3) + struct ::stat file_stat; +#else + struct stat file_stat; +#endif + + bool bStatNeeded = is_stat_call_necessary(uFieldMask, pImpl->getFileType()); + if (bStatNeeded && (0 != osl::lstat(file_path, file_stat))) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + if (bStatNeeded) + { + // we set all these attributes because it's cheap + set_file_type(file_stat, pStat); + set_file_access_time(file_stat, pStat); + set_file_modify_time(file_stat, pStat); + set_file_size(file_stat, pStat); + set_file_attributes(file_path, file_stat, uFieldMask, pStat); + + // file exists semantic of osl_FileStatus_Mask_Validate + if ((uFieldMask & osl_FileStatus_Mask_LinkTargetURL) && S_ISLNK(file_stat.st_mode)) + { + osl_error = set_link_target_url(file_path, pStat); + if (osl_error != osl_File_E_None) + return osl_error; + } + } +#ifdef _DIRENT_HAVE_D_TYPE + else if (uFieldMask & osl_FileStatus_Mask_Type) + { + pStat->eType = pImpl->getFileType(); + pStat->uValidFields |= osl_FileStatus_Mask_Type; + } +#endif /* _DIRENT_HAVE_D_TYPE */ + + if (uFieldMask & osl_FileStatus_Mask_FileURL) + { + if ((osl_error = osl_getFileURLFromSystemPath(file_path.pData, &pStat->ustrFileURL)) != osl_File_E_None) + return osl_error; + + pStat->uValidFields |= osl_FileStatus_Mask_FileURL; + } + + if (uFieldMask & osl_FileStatus_Mask_FileName) + { + osl_systemPathGetFileNameOrLastDirectoryPart(file_path.pData, &pStat->ustrFileName); + pStat->uValidFields |= osl_FileStatus_Mask_FileName; + } + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_setFileAttributes */ +/****************************************************************************/ + +static oslFileError osl_psz_setFileAttributes( const sal_Char* pszFilePath, sal_uInt64 uAttributes ) +{ + oslFileError osl_error = osl_File_E_None; + mode_t nNewMode = 0; + + OSL_ENSURE(!(osl_File_Attribute_Hidden & uAttributes), "osl_File_Attribute_Hidden doesn't work under Unix"); + + if (uAttributes & osl_File_Attribute_OwnRead) + nNewMode |= S_IRUSR; + + if (uAttributes & osl_File_Attribute_OwnWrite) + nNewMode|=S_IWUSR; + + if (uAttributes & osl_File_Attribute_OwnExe) + nNewMode|=S_IXUSR; + + if (uAttributes & osl_File_Attribute_GrpRead) + nNewMode|=S_IRGRP; + + if (uAttributes & osl_File_Attribute_GrpWrite) + nNewMode|=S_IWGRP; + + if (uAttributes & osl_File_Attribute_GrpExe) + nNewMode|=S_IXGRP; + + if (uAttributes & osl_File_Attribute_OthRead) + nNewMode|=S_IROTH; + + if (uAttributes & osl_File_Attribute_OthWrite) + nNewMode|=S_IWOTH; + + if (uAttributes & osl_File_Attribute_OthExe) + nNewMode|=S_IXOTH; + + if (chmod(pszFilePath, nNewMode) < 0) + osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); + + return osl_error; +} + +oslFileError SAL_CALL osl_setFileAttributes( rtl_uString* ustrFileURL, sal_uInt64 uAttributes ) +{ + 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; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_setFileAttributes( path, uAttributes ); +} + +/****************************************************************************/ +/* osl_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; +} + +oslFileError SAL_CALL 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; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_setFileTime( path, pCreationTime, pLastAccessTime, pLastWriteTime ); +} diff --git a/sal/osl/unx/file_url.cxx b/sal/osl/unx/file_url.cxx new file mode 100644 index 000000000000..26290957f802 --- /dev/null +++ b/sal/osl/unx/file_url.cxx @@ -0,0 +1,962 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "file_url.h" + +#include "system.h" + +#include <limits.h> +#include <errno.h> +#include <strings.h> +#include <unistd.h> + +#include "osl/file.hxx" +#include <osl/security.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/process.h> + +#include <rtl/uri.h> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.h> +#include "rtl/textcvt.h" + +#include "file_error_transl.h" +#include "file_path_helper.hxx" + +#include "uunxapi.hxx" + +/*************************************************** + + General note + + This file contains the part that handles File URLs. + + File URLs as scheme specific notion of URIs + (RFC2396) may be handled platform independend, but + will not in osl which is considered wrong. + Future version of osl should handle File URLs this + way. In rtl/uri there is already an URI parser etc. + so this code should be consolidated. + + **************************************************/ +/************************************************************************ + * ToDo + * + * Fix osl_getCanonicalName + * + ***********************************************************************/ + + +/*************************************************** + * namespace directives + **************************************************/ + +using namespace osl; + +/*************************************************** + * constants + **************************************************/ + +const sal_Unicode UNICHAR_SLASH = ((sal_Unicode)'/'); +const sal_Unicode UNICHAR_COLON = ((sal_Unicode)':'); +const sal_Unicode UNICHAR_DOT = ((sal_Unicode)'.'); + +/****************************************************************************** + * + * Exported Module Functions + * + *****************************************************************************/ + +/* a slightly modified version of Pchar in rtl/source/uri.c */ +const sal_Bool uriCharClass[128] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /* pqrstuvwxyz{|}~ */ +}; + + +/* check for top wrong usage strings */ +/* +static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len ) +{ + rtl_uString *pTmp = NULL; + sal_Bool bRet; + + rtl_uString_newFromStr_WithLength( &pTmp, path, len ); + + rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length ); + + bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) ); + + rtl_uString_release( pTmp ); + return bRet; +} +*/ + +/****************************************************************************/ +/* osl_getCanonicalName */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uString** pustrValidURL ) +{ + OSL_ENSURE(0, "osl_getCanonicalName not implemented"); + + rtl_uString_newFromString(pustrValidURL, ustrFileURL); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_getSystemPathFromFileURL */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath ) +{ + sal_Int32 nIndex; + rtl_uString * pTmp = NULL; + + sal_Unicode encodedSlash[3] = { '%', '2', 'F' }; + sal_Unicode protocolDelimiter[3] = { ':', '/', '/' }; + + /* temporary hack: if already system path, return ustrFileURL */ + /* + if( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) + { + OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" ); + rtl_uString_assign( pustrSystemPath, ustrFileURL ); + return osl_File_E_None; + } + */ + + /* a valid file url may not start with '/' */ + if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) ) + { + return osl_File_E_INVAL; + } + + /* Check for non file:// protocols */ + + nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 ); + if ( -1 != nIndex && (4 != nIndex || 0 != rtl_ustr_ascii_shortenedCompare_WithLength( ustrFileURL->buffer, ustrFileURL->length,"file", 4 ) ) ) + { + return osl_File_E_INVAL; + } + + /* search for encoded slashes (%2F) and decode every single token if we find one */ + + nIndex = 0; + + if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) ) + { + rtl_uString * ustrPathToken = NULL; + sal_Int32 nOffset = 7; + + do + { + nOffset += nIndex; + + /* break url down in '/' devided tokens tokens */ + nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' ); + + /* copy token to new string */ + rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset, + -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ ); + + /* decode token */ + rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); + + /* the result should not contain any '/' */ + if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) ) + { + rtl_uString_release( pTmp ); + rtl_uString_release( ustrPathToken ); + + return osl_File_E_INVAL; + } + + } while( -1 != nIndex ); + + /* release temporary string and restore index variable */ + rtl_uString_release( ustrPathToken ); + nIndex = 0; + } + + /* protocol and server should not be encoded, so decode the whole string */ + rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); + + /* check if file protocol specified */ + /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ + if( 7 <= pTmp->length ) + { + rtl_uString * pProtocol = NULL; + rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 ); + + /* protocol is case insensitive */ + rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length ); + + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) ) + nIndex = 7; + + rtl_uString_release( pProtocol ); + } + + /* skip "localhost" or "127.0.0.1" if "file://" is specified */ + /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ + if( nIndex && ( 10 <= pTmp->length - nIndex ) ) + { + rtl_uString * pServer = NULL; + rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 ); + + /* server is case insensitive */ + rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length ); + + if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) ) + { + /* don't exclude the '/' */ + nIndex += 9; + } + + rtl_uString_release( pServer ); + } + + if( nIndex ) + rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex ); + + /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ + if( (sal_Unicode) '~' == pTmp->buffer[0] ) + { + /* check if another user is specified */ + if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) ) + { + rtl_uString *pTmp2 = NULL; + + /* osl_getHomeDir returns file URL */ + osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 ); + + /* remove "file://" prefix */ + rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 ); + + /* replace '~' in original string */ + rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 ); + rtl_uString_release( pTmp2 ); + } + + else + { + /* FIXME: replace ~user with users home directory */ + return osl_File_E_INVAL; + } + } + + /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ + /* + OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); + */ + + *pustrSystemPath = pTmp; + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_getFileURLFromSystemPath */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL ) +{ + static const sal_Unicode pDoubleSlash[2] = { '/', '/' }; + + rtl_uString *pTmp = NULL; + sal_Int32 nIndex; + + if( 0 == ustrSystemPath->length ) + return osl_File_E_INVAL; + + /* temporary hack: if already file url, return ustrSystemPath */ + + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) ) + { + /* + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) ) + { + OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" ); + rtl_uString_assign( pustrFileURL, ustrSystemPath ); + } + else + { + rtl_uString *pTmp2 = NULL; + + OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" ); + rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 ); + rtl_uString_newFromAscii( &pTmp2, "file://" ); + rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 ); + rtl_uString_release( pTmp2 ); + } + return osl_File_E_None; + */ + return osl_File_E_INVAL; + } + + + /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ + if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] ) + { + /* check if another user is specified */ + if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) ) + { + /* osl_getHomeDir returns file URL */ + osl_getHomeDir( osl_getCurrentSecurity(), &pTmp ); + + /* remove "file://" prefix */ + rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 ); + + /* replace '~' in original string */ + rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp ); + } + + else + { + /* FIXME: replace ~user with users home directory */ + return osl_File_E_INVAL; + } + } + + /* check if initial string contains double instances of '/' */ + nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 ); + if( -1 != nIndex ) + { + sal_Int32 nSrcIndex; + sal_Int32 nDeleted = 0; + + /* if pTmp is not already allocated, copy ustrSystemPath for modification */ + if( NULL == pTmp ) + rtl_uString_newFromString( &pTmp, ustrSystemPath ); + + /* adapt index to pTmp */ + nIndex += pTmp->length - ustrSystemPath->length; + + /* remove all occurances of '//' */ + for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ ) + { + if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) ) + nDeleted++; + else + pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex]; + } + + /* adjust length member */ + pTmp->length -= nDeleted; + } + + if( NULL == pTmp ) + rtl_uString_assign( &pTmp, ustrSystemPath ); + + /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ + /* + OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); + */ + + /* file URLs must be URI encoded */ + rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL ); + + rtl_uString_release( pTmp ); + + /* absolute urls should start with 'file://' */ + if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] ) + { + rtl_uString *pProtocol = NULL; + + rtl_uString_newFromAscii( &pProtocol, "file://" ); + rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL ); + rtl_uString_release( pProtocol ); + } + + return osl_File_E_None; +} + +/**************************************************************************** + * osl_getSystemPathFromFileURL_Ex - helper function + * clients may specify if they want to accept relative + * URLs or not + ****************************************************************************/ + +oslFileError osl_getSystemPathFromFileURL_Ex( + rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative) +{ + rtl_uString* temp = 0; + oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp); + + if (osl_File_E_None == osl_error) + { + if (bAllowRelative || (UNICHAR_SLASH == temp->buffer[0])) + { + *pustrSystemPath = temp; + } + else + { + rtl_uString_release(temp); + osl_error = osl_File_E_INVAL; + } + } + + return osl_error; +} + +namespace /* private */ +{ + + /****************************************************** + * Helper function, return a pinter to the final '\0' + * of a string + ******************************************************/ + + sal_Unicode* ustrtoend(sal_Unicode* pStr) + { + return (pStr + rtl_ustr_getLength(pStr)); + } + + /********************************************* + + ********************************************/ + + sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d) + { + sal_Unicode* p = ustrtoend(d); + *p++ = chr; + *p = 0; + return d; + } + + /****************************************************** + * + ******************************************************/ + + bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr) + { + sal_Unicode* p = ustrtoend(pStr); + if (p > pStr) + p--; + return (*p == Chr); + } + + /****************************************************** + * Remove the last part of a path, a path that has + * only a '/' or no '/' at all will be returned + * unmodified + ******************************************************/ + + sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath) + { + /* we always may skip -2 because we + may at least stand on a '/' but + either there is no other character + before this '/' or it's another + character than the '/' + */ + sal_Unicode* p = ustrtoend(aPath) - 2; + + // move back to the next path separator + // or to the start of the string + while ((p > aPath) && (*p != UNICHAR_SLASH)) + p--; + + if (p >= aPath) + { + if (UNICHAR_SLASH == *p) + { + p++; + *p = '\0'; + } + else + { + *p = '\0'; + } + } + + return aPath; + } + + /****************************************************** + * + ******************************************************/ + + oslFileError _osl_resolvepath( + /*inout*/ sal_Unicode* path, + /*inout*/ sal_Unicode* current_pos, + /*inout*/ bool* failed) + { + oslFileError ferr = osl_File_E_None; + + if (!*failed) + { + char unresolved_path[PATH_MAX]; + if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path))) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + char resolved_path[PATH_MAX]; + if (realpath(unresolved_path, resolved_path)) + { + if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX)) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + current_pos = ustrtoend(path) - 1; + } + else + { + if (EACCES == errno || ENOTDIR == errno || ENOENT == errno) + *failed = true; + else + ferr = oslTranslateFileError(OSL_FET_ERROR, errno); + } + } + + return ferr; + } + + /****************************************************** + * Works even with non existing paths. The resulting + * path must not exceed PATH_MAX else + * osl_File_E_NAMETOOLONG is the result + ******************************************************/ + + oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path) + { + // the given unresolved path must not exceed PATH_MAX + if (unresolved_path.getLength() >= (PATH_MAX - 2)) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + sal_Unicode path_resolved_so_far[PATH_MAX]; + const sal_Unicode* punresolved = unresolved_path.getStr(); + sal_Unicode* presolvedsf = path_resolved_so_far; + + // reserve space for leading '/' and trailing '\0' + // do not exceed this limit + sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2; + + // if realpath fails with error ENOTDIR, EACCES or ENOENT + // we will not call it again, because _osl_realpath should also + // work with non existing directories etc. + bool realpath_failed = false; + oslFileError ferr; + + path_resolved_so_far[0] = '\0'; + + while (*punresolved != '\0') + { + // ignore '/.' , skip one part back when '/..' + + if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf)) + { + if ('\0' == *(punresolved + 1)) + { + punresolved++; + continue; + } + else if (UNICHAR_SLASH == *(punresolved + 1)) + { + punresolved += 2; + continue; + } + else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2)))) + { + _rmlastpathtoken(path_resolved_so_far); + + presolvedsf = ustrtoend(path_resolved_so_far) - 1; + + if (UNICHAR_SLASH == *(punresolved + 2)) + punresolved += 3; + else + punresolved += 2; + + continue; + } + else // a file or directory name may start with '.' + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if ('\0' == *punresolved && !realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + } + } + } + else if (UNICHAR_SLASH == *punresolved) + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if (!realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + + if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH)) + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(UNICHAR_SLASH, path_resolved_so_far); + } + } + } + else // any other character + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if ('\0' == *punresolved && !realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + } + } + } + + sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far); + + OSL_ASSERT(len < PATH_MAX); + + resolved_path = rtl::OUString(path_resolved_so_far, len); + + return osl_File_E_None; + } + +} // end namespace private + + +/****************************************************** + * osl_getAbsoluteFileURL + ******************************************************/ + +oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL) +{ + FileBase::RC rc; + rtl::OUString unresolved_path; + + rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path); + + if(FileBase::E_None != rc) + return oslFileError(rc); + + if (systemPathIsRelativePath(unresolved_path)) + { + rtl::OUString base_path; + rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False); + + if (FileBase::E_None != rc) + return oslFileError(rc); + + rtl::OUString abs_path; + systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path); + + unresolved_path = abs_path; + } + + rtl::OUString resolved_path; + rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path); + + if (FileBase::E_None == rc) + { + rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL); + OSL_ASSERT(FileBase::E_None == rc); + } + + return oslFileError(rc); +} + + +namespace /* private */ +{ + + /********************************************* + No separate error code if unicode to text + conversion or getenv fails because for the + caller there is no difference why a file + could not be found in $PATH + ********************************************/ + + bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result) + { + bool bfound = false; + rtl::OUString path = rtl::OUString::createFromAscii("PATH"); + rtl::OUString env_path; + + if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData)) + bfound = osl::searchPath(file_path, env_path, result); + + return bfound; + } + + /********************************************* + No separate error code if unicode to text + conversion or getcwd fails because for the + caller there is no difference why a file + could not be found in CDW + ********************************************/ + + bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result) + { + bool bfound = false; + rtl::OUString cwd_url; + + if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData)) + { + rtl::OUString cwd; + FileBase::getSystemPathFromFileURL(cwd_url, cwd); + bfound = osl::searchPath(file_path, cwd, result); + } + return bfound; + } + + /********************************************* + + ********************************************/ + + bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result) + { + return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result)); + } + +} // end namespace private + + +/**************************************************************************** + * osl_searchFileURL + ***************************************************************************/ + +oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL) +{ + OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter"); + + FileBase::RC rc; + rtl::OUString file_path; + + // try to interpret search path as file url else assume it's a system path list + rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path); + if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc)) + file_path = ustrFilePath; + else if (FileBase::E_None != rc) + return oslFileError(rc); + + bool bfound = false; + rtl::OUString result; + + if (find_in_searchPath(file_path, ustrSearchPath, result) || + find_in_PATH(file_path, result) || + find_in_CWD(file_path, result)) + { + rtl::OUString resolved; + + if (osl::realpath(result, resolved)) + { +#if OSL_DEBUG_LEVEL > 0 + oslFileError osl_error = +#endif + osl_getFileURLFromSystemPath(resolved.pData, pustrURL); + OSL_ASSERT(osl_File_E_None == osl_error); + bfound = true; + } + } + return bfound ? osl_File_E_None : osl_File_E_NOENT; +} + + +/**************************************************************************** + * FileURLToPath + ***************************************************************************/ + +oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath); + + if(osl_File_E_None != osl_error) + return osl_error; + + osl_systemPathRemoveSeparator(ustrSystemPath); + + /* convert unicode path to text */ + if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length)) + osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); + + rtl_uString_release(ustrSystemPath); + + return osl_error; +} + +/***************************************************************************** + * UnicodeToText + ****************************************************************************/ + +namespace /* private */ +{ + class UnicodeToTextConverter_Impl + { + rtl_UnicodeToTextConverter m_converter; + + UnicodeToTextConverter_Impl() + : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding())) + {} + + ~UnicodeToTextConverter_Impl() + { + rtl_destroyUnicodeToTextConverter (m_converter); + } + public: + static UnicodeToTextConverter_Impl & getInstance() + { + static UnicodeToTextConverter_Impl g_theConverter; + return g_theConverter; + } + + sal_Size convert( + sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes, + sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars) + { + OSL_ASSERT(m_converter != 0); + return rtl_convertUnicodeToText ( + m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars); + } + }; +} // end namespace private + +int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen ) +{ + sal_uInt32 nInfo = 0; + sal_Size nSrcChars = 0; + + sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert ( + uniText, uniTextLen, buffer, bufLen, + OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars); + + if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL ) + { + errno = EOVERFLOW; + return 0; + } + + /* ensure trailing '\0' */ + buffer[nDestBytes] = '\0'; + return nDestBytes; +} + +/***************************************************************************** + * TextToUnicode + ****************************************************************************/ + +namespace /* private */ +{ + class TextToUnicodeConverter_Impl + { + rtl_TextToUnicodeConverter m_converter; + + TextToUnicodeConverter_Impl() + : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding())) + {} + + ~TextToUnicodeConverter_Impl() + { + rtl_destroyTextToUnicodeConverter (m_converter); + } + + public: + static TextToUnicodeConverter_Impl & getInstance() + { + static TextToUnicodeConverter_Impl g_theConverter; + return g_theConverter; + } + + sal_Size convert( + sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars, + sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes) + { + OSL_ASSERT(m_converter != 0); + return rtl_convertTextToUnicode ( + m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes); + } + }; +} // end namespace private + +int TextToUnicode( + const char* text, + size_t text_buffer_size, + sal_Unicode* unic_text, + sal_Int32 unic_text_buffer_size) +{ + sal_uInt32 nInfo = 0; + sal_Size nSrcChars = 0; + + sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert( + text, text_buffer_size, unic_text, unic_text_buffer_size, + OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars); + + if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL) + { + errno = EOVERFLOW; + return 0; + } + + /* ensure trailing '\0' */ + unic_text[nDestBytes] = '\0'; + return nDestBytes; +} diff --git a/sal/osl/unx/file_url.h b/sal/osl/unx/file_url.h new file mode 100644 index 000000000000..0a0d07823bba --- /dev/null +++ b/sal/osl/unx/file_url.h @@ -0,0 +1,69 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_FILE_URL_H +#define INCLUDED_FILE_URL_H + +#include "osl/file.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************** + * osl_getSystemPathFromFileURL_Ex + *************************************************/ + +#define FURL_ALLOW_RELATIVE sal_True +#define FURL_DENY_RELATIVE sal_False + +oslFileError osl_getSystemPathFromFileURL_Ex(rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative); + +/************************************************** + * FileURLToPath + *************************************************/ + +oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL); + +/*************************************************** + * UnicodeToText + **************************************************/ + +int UnicodeToText(char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen); + +/*************************************************** + * TextToUniCode + **************************************************/ + +int TextToUnicode(const char* text, size_t text_buffer_size, sal_Unicode* unic_text, sal_Int32 unic_text_buffer_size); + +#ifdef __cplusplus +} +#endif + +#endif /* #define INCLUDED_FILE_URL_H */ diff --git a/sal/osl/unx/file_volume.cxx b/sal/osl/unx/file_volume.cxx new file mode 100644 index 000000000000..cc7f61ec6a8b --- /dev/null +++ b/sal/osl/unx/file_volume.cxx @@ -0,0 +1,1155 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/file.h" + +#include "osl/diagnose.h" +#include "osl/thread.h" +#include "rtl/alloc.h" + +#include "file_error_transl.h" +#include "file_url.h" +#include "system.h" + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> + +#ifdef HAVE_STATFS_H +#undef HAVE_STATFS_H +#endif + +#if defined(LINUX) && defined(__FreeBSD_kernel__) +#undef LINUX +#define FREEBSD 1 +#endif + + +#if defined(SOLARIS) + +#include <sys/mnttab.h> +#include <sys/statvfs.h> +#define HAVE_STATFS_H +#include <sys/fs/ufs_quota.h> +static const sal_Char* MOUNTTAB="/etc/mnttab"; + +#elif defined(LINUX) + +#include <mntent.h> +#include <sys/vfs.h> +#define HAVE_STATFS_H +#include <sys/quota.h> +//#include <ctype.h> +static const sal_Char* MOUNTTAB="/etc/mtab"; + +#elif defined(NETBSD) || defined(FREEBSD) + +#include <sys/param.h> +#include <sys/ucred.h> +#include <sys/mount.h> +#include <ufs/ufs/quota.h> +//#include <ctype.h> +#define HAVE_STATFS_H + +/* No mounting table on *BSD + * This information is stored only in the kernel. */ +/* static const sal_Char* MOUNTTAB="/etc/mtab"; */ + +#elif defined(MACOSX) + +#include <ufs/ufs/quota.h> +//#include <ctype.h> +#include <sys/param.h> +#include <sys/mount.h> +#define HAVE_STATFS_H +// static const sal_Char* MOUNTTAB="/etc/mtab"; + +#endif /* HAVE_STATFS_H */ + +/************************************************************************ + * ToDo + * + * - Fix: check for corresponding struct sizes in exported functions + * - check size/use of oslVolumeDeviceHandle + * - check size/use of oslVolumeInfo + ***********************************************************************/ +/****************************************************************************** + * + * Data Type Definition + * + ******************************************************************************/ + +typedef struct _oslVolumeDeviceHandleImpl +{ + sal_Char pszMountPoint[PATH_MAX]; + sal_Char pszFilePath[PATH_MAX]; + sal_Char pszDevice[PATH_MAX]; + sal_Char ident[4]; + sal_uInt32 RefCount; +} oslVolumeDeviceHandleImpl; + +/****************************************************************************** + * + * '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); + +#if defined(SOLARIS) +static sal_Bool osl_isFloppyMounted(sal_Char* pszPath, sal_Char* pszMountPath); +static sal_Bool osl_getFloppyMountEntry(const sal_Char* pszPath, sal_Char* pBuffer); +static sal_Bool osl_checkFloppyPath(sal_Char* pszPath, sal_Char* pszFilePath, sal_Char* pszDevicePath); +#endif /* SOLARIS */ + +#if defined(LINUX) +static sal_Bool osl_isFloppyMounted(oslVolumeDeviceHandleImpl* pDevice); +static sal_Bool osl_getFloppyMountEntry(const sal_Char* pszPath, oslVolumeDeviceHandleImpl* pItem); +#endif /* LINUX */ + +#ifdef DEBUG_OSL_FILE +static void osl_printFloppyHandle(oslVolumeDeviceHandleImpl* hFloppy); +#endif /* DEBUG_OSL_FILE */ + +/****************************************************************************** + * + * C-String Function Declarations + * + *****************************************************************************/ + +static oslFileError osl_psz_getVolumeInformation(const sal_Char* , oslVolumeInfo* pInfo, sal_uInt32 uFieldMask); + +/****************************************************************************/ +/* osl_getVolumeInformation */ +/****************************************************************************/ + +oslFileError osl_getVolumeInformation( rtl_uString* ustrDirectoryURL, oslVolumeInfo* pInfo, sal_uInt32 uFieldMask ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrDirectoryURL ); + OSL_ASSERT( pInfo ); + + /* convert directory url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_getVolumeInformation( path, pInfo, uFieldMask); +} + +/****************************************************************************** + * + * C-String Versions of Exported Module Functions + * + *****************************************************************************/ + +#ifdef HAVE_STATFS_H + +#if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) +# define __OSL_STATFS_STRUCT struct statfs +# define __OSL_STATFS(dir, sfs) statfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_bsize)) +# define __OSL_STATFS_TYPENAME(a) ((a).f_fstypename) +# define __OSL_STATFS_ISREMOTE(a) (((a).f_type & MNT_LOCAL) == 0) + +/* always return true if queried for the properties of + the file system. If you think this is wrong under any + of the target platforms fix it!!!! */ +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* FREEBSD || NETBSD || MACOSX */ + +#if defined(LINUX) +# define __OSL_NFS_SUPER_MAGIC 0x6969 +# define __OSL_SMB_SUPER_MAGIC 0x517B +# define __OSL_MSDOS_SUPER_MAGIC 0x4d44 +# define __OSL_NTFS_SUPER_MAGIC 0x5346544e +# define __OSL_STATFS_STRUCT struct statfs +# define __OSL_STATFS(dir, sfs) statfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_bsize)) +# define __OSL_STATFS_IS_NFS(a) (__OSL_NFS_SUPER_MAGIC == (a).f_type) +# define __OSL_STATFS_IS_SMB(a) (__OSL_SMB_SUPER_MAGIC == (a).f_type) +# define __OSL_STATFS_ISREMOTE(a) (__OSL_STATFS_IS_NFS((a)) || __OSL_STATFS_IS_SMB((a))) +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) ((__OSL_MSDOS_SUPER_MAGIC != (a).f_type) && (__OSL_NTFS_SUPER_MAGIC != (a).f_type)) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) ((__OSL_MSDOS_SUPER_MAGIC != (a).f_type)) +#endif /* LINUX */ + +#if defined(SOLARIS) +# define __OSL_STATFS_STRUCT struct statvfs +# define __OSL_STATFS(dir, sfs) statvfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_frsize)) +# define __OSL_STATFS_TYPENAME(a) ((a).f_basetype) +# define __OSL_STATFS_ISREMOTE(a) (rtl_str_compare((a).f_basetype, "nfs") == 0) + +/* always return true if queried for the properties of + the file system. If you think this is wrong under any + of the target platforms fix it!!!! */ +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* SOLARIS */ + +# define __OSL_STATFS_INIT(a) (memset(&(a), 0, sizeof(__OSL_STATFS_STRUCT))) + +#else /* no statfs available */ + +# define __OSL_STATFS_STRUCT struct dummy {int i;} +# define __OSL_STATFS_INIT(a) ((void)0) +# define __OSL_STATFS(dir, sfs) (1) +# define __OSL_STATFS_ISREMOTE(sfs) (0) +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* HAVE_STATFS_H */ + + +static oslFileError osl_psz_getVolumeInformation ( + const sal_Char* pszDirectory, oslVolumeInfo* pInfo, sal_uInt32 uFieldMask) +{ + __OSL_STATFS_STRUCT sfs; + + if (!pInfo) + return osl_File_E_INVAL; + + __OSL_STATFS_INIT(sfs); + + pInfo->uValidFields = 0; + pInfo->uAttributes = 0; + + if ((__OSL_STATFS(pszDirectory, &sfs)) < 0) + { + oslFileError result = oslTranslateFileError(OSL_FET_ERROR, errno); + return (result); + } + + /* FIXME: how to detect the kind of storage (fixed, cdrom, ...) */ + if (uFieldMask & osl_VolumeInfo_Mask_Attributes) + { + if (__OSL_STATFS_ISREMOTE(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Remote; + + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + + if (uFieldMask & osl_VolumeInfo_Mask_FileSystemCaseHandling) + { + if (__OSL_STATFS_IS_CASE_SENSITIVE_FS(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Case_Sensitive; + + if (__OSL_STATFS_IS_CASE_PRESERVING_FS(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved; + + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + + pInfo->uTotalSpace = 0; + pInfo->uFreeSpace = 0; + pInfo->uUsedSpace = 0; + +#if defined(__OSL_STATFS_BLKSIZ) + + if ((uFieldMask & osl_VolumeInfo_Mask_TotalSpace) || + (uFieldMask & osl_VolumeInfo_Mask_UsedSpace)) + { + pInfo->uTotalSpace = __OSL_STATFS_BLKSIZ(sfs); + pInfo->uTotalSpace *= (sal_uInt64)(sfs.f_blocks); + pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace; + } + + if ((uFieldMask & osl_VolumeInfo_Mask_FreeSpace) || + (uFieldMask & osl_VolumeInfo_Mask_UsedSpace)) + { + pInfo->uFreeSpace = __OSL_STATFS_BLKSIZ(sfs); + + if (getuid() == 0) + pInfo->uFreeSpace *= (sal_uInt64)(sfs.f_bfree); + else + pInfo->uFreeSpace *= (sal_uInt64)(sfs.f_bavail); + + pInfo->uValidFields |= osl_VolumeInfo_Mask_FreeSpace; + } + +#endif /* __OSL_STATFS_BLKSIZ */ + + if ((pInfo->uValidFields & osl_VolumeInfo_Mask_TotalSpace) && + (pInfo->uValidFields & osl_VolumeInfo_Mask_FreeSpace )) + { + pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace; + pInfo->uValidFields |= osl_VolumeInfo_Mask_UsedSpace; + } + + pInfo->uMaxNameLength = 0; + if (uFieldMask & osl_VolumeInfo_Mask_MaxNameLength) + { + long nLen = pathconf(pszDirectory, _PC_NAME_MAX); + if (nLen > 0) + { + pInfo->uMaxNameLength = (sal_uInt32)nLen; + pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength; + } + } + + pInfo->uMaxPathLength = 0; + if (uFieldMask & osl_VolumeInfo_Mask_MaxPathLength) + { + long nLen = pathconf (pszDirectory, _PC_PATH_MAX); + if (nLen > 0) + { + pInfo->uMaxPathLength = (sal_uInt32)nLen; + pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength; + } + } + +#if defined(__OSL_STATFS_TYPENAME) + + if (uFieldMask & osl_VolumeInfo_Mask_FileSystemName) + { + rtl_string2UString( + &(pInfo->ustrFileSystemName), + __OSL_STATFS_TYPENAME(sfs), + rtl_str_getLength(__OSL_STATFS_TYPENAME(sfs)), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS); + OSL_ASSERT(pInfo->ustrFileSystemName != 0); + + pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName; + } + +#endif /* __OSL_STATFS_TYPENAME */ + + if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle) + { + /* FIXME: check also entries in mntent for the device + and fill it with correct values */ + + *pInfo->pDeviceHandle = osl_isFloppyDrive(pszDirectory); + + if (*pInfo->pDeviceHandle) + { + pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle; + pInfo->uAttributes |= osl_Volume_Attribute_Removeable; + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + } + return osl_File_E_None; +} + +/****************************************************************************** + * + * GENERIC FLOPPY FUNCTIONS + * + *****************************************************************************/ + + +/***************************************** + * osl_unmountVolumeDevice + ****************************************/ + +oslFileError osl_unmountVolumeDevice( oslVolumeDeviceHandle Handle ) +{ + oslFileError tErr = osl_File_E_NOSYS; + + tErr = osl_unmountFloppy(Handle); + + /* Perhaps current working directory is set to mount point */ + + if ( tErr ) + { + sal_Char *pszHomeDir = getenv("HOME"); + + if ( pszHomeDir && strlen( pszHomeDir ) && 0 == chdir( pszHomeDir ) ) + { + /* try again */ + + tErr = osl_unmountFloppy(Handle); + + OSL_ENSURE( tErr, "osl_unmountvolumeDevice: CWD was set to volume mount point" ); + } + } + + return tErr; +} + +/***************************************** + * osl_automountVolumeDevice + ****************************************/ + +oslFileError osl_automountVolumeDevice( oslVolumeDeviceHandle Handle ) +{ + oslFileError tErr = osl_File_E_NOSYS; + + tErr = osl_mountFloppy(Handle); + + return tErr; +} + +/***************************************** + * osl_getVolumeDeviceMountPath + ****************************************/ +static 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; +} + +oslFileError osl_getVolumeDeviceMountPath( oslVolumeDeviceHandle Handle, rtl_uString **pstrPath ) +{ + oslVolumeDeviceHandleImpl* pItem = (oslVolumeDeviceHandleImpl*) Handle; + sal_Char Buffer[PATH_MAX]; + + Buffer[0] = '\0'; + + if ( pItem == 0 || pstrPath == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"Handle is:\n"); + osl_printFloppyHandle(pItem); +#endif + + snprintf(Buffer, sizeof(Buffer), "file://%s", pItem->pszMountPoint); + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"Mount Point is: '%s'\n",Buffer); +#endif + + oslMakeUStrFromPsz(Buffer, pstrPath); + + return osl_File_E_None; +} + +/***************************************** + * osl_acquireVolumeDeviceHandle + ****************************************/ + +oslFileError SAL_CALL osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle ) +{ + oslVolumeDeviceHandleImpl* pItem =(oslVolumeDeviceHandleImpl*) Handle; + + if ( pItem == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + + ++pItem->RefCount; + + return osl_File_E_None; +} + +/***************************************** + * osl_releaseVolumeDeviceHandle + ****************************************/ + +oslFileError osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle ) +{ + oslVolumeDeviceHandleImpl* pItem =(oslVolumeDeviceHandleImpl*) Handle; + + if ( pItem == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + + --pItem->RefCount; + + if ( pItem->RefCount == 0 ) + { + rtl_freeMemory(pItem); + } + + return osl_File_E_None; +} + +#ifndef MACOSX + +/***************************************** + * osl_newVolumeDeviceHandleImpl + ****************************************/ + +static oslVolumeDeviceHandleImpl* osl_newVolumeDeviceHandleImpl() +{ + oslVolumeDeviceHandleImpl* pHandle; + const size_t nSizeOfHandle = sizeof(oslVolumeDeviceHandleImpl); + + pHandle = (oslVolumeDeviceHandleImpl*) rtl_allocateMemory (nSizeOfHandle); + if (pHandle != NULL) + { + pHandle->ident[0] = 'O'; + pHandle->ident[1] = 'V'; + pHandle->ident[2] = 'D'; + pHandle->ident[3] = 'H'; + pHandle->pszMountPoint[0] = '\0'; + pHandle->pszFilePath[0] = '\0'; + pHandle->pszDevice[0] = '\0'; + pHandle->RefCount = 1; + } + return pHandle; +} + +/***************************************** + * osl_freeVolumeDeviceHandleImpl + ****************************************/ + +static void osl_freeVolumeDeviceHandleImpl (oslVolumeDeviceHandleImpl* pHandle) +{ + if (pHandle != NULL) + rtl_freeMemory (pHandle); +} +#endif + +/****************************************************************************** + * + * SOLARIS FLOPPY FUNCTIONS + * + *****************************************************************************/ + +#if defined(SOLARIS) +/* compare a given devicename with the typical device names on a Solaris box */ +static sal_Bool +osl_isAFloppyDevice (const char* pDeviceName) +{ + const char* pFloppyDevice [] = { + "/dev/fd", "/dev/rfd", + "/dev/diskette", "/dev/rdiskette", + "/vol/dev/diskette", "/vol/dev/rdiskette" + }; + + int i; + for (i = 0; i < (sizeof(pFloppyDevice)/sizeof(pFloppyDevice[0])); i++) + { + if (strncmp(pDeviceName, pFloppyDevice[i], strlen(pFloppyDevice[i])) == 0) + return sal_True; + } + return sal_False; +} + +/* compare two directories whether the first may be a parent of the second. this + * does not realpath() resolving */ +static sal_Bool +osl_isAParentDirectory (const char* pParentDir, const char* pSubDir) +{ + return strncmp(pParentDir, pSubDir, strlen(pParentDir)) == 0; +} + +/* the name of the routine is obviously silly. But anyway create a + * oslVolumeDeviceHandle with correct mount point, device name and a resolved filepath + * only if pszPath points to file or directory on a floppy */ +static oslVolumeDeviceHandle +osl_isFloppyDrive(const sal_Char* pszPath) +{ + FILE* pMountTab; + struct mnttab aMountEnt; + oslVolumeDeviceHandleImpl* pHandle; + + if ((pHandle = osl_newVolumeDeviceHandleImpl()) == NULL) + { + return NULL; + } + if (realpath(pszPath, pHandle->pszFilePath) == NULL) + { + osl_freeVolumeDeviceHandleImpl (pHandle); + return NULL; + } + if ((pMountTab = fopen (MOUNTTAB, "r")) == NULL) + { + osl_freeVolumeDeviceHandleImpl (pHandle); + return NULL; + } + + while (getmntent(pMountTab, &aMountEnt) == 0) + { + const char *pMountPoint = aMountEnt.mnt_mountp; + const char *pDevice = aMountEnt.mnt_special; + if ( osl_isAParentDirectory (aMountEnt.mnt_mountp, pHandle->pszFilePath) + && osl_isAFloppyDevice (aMountEnt.mnt_special)) + { + /* skip the last item for it is the name of the disk */ + char * pc = strrchr( aMountEnt.mnt_special, '/' ); + + if ( NULL != pc ) + { + int len = pc - aMountEnt.mnt_special; + + strncpy( pHandle->pszDevice, aMountEnt.mnt_special, len ); + pHandle->pszDevice[len] = '\0'; + } + else + { + /* #106048 use save str functions to avoid buffer overflows */ + memset(pHandle->pszDevice, 0, sizeof(pHandle->pszDevice)); + strncpy(pHandle->pszDevice, aMountEnt.mnt_special, sizeof(pHandle->pszDevice) - 1); + } + + /* remember the mount point */ + memset(pHandle->pszMountPoint, 0, sizeof(pHandle->pszMountPoint)); + strncpy(pHandle->pszMountPoint, aMountEnt.mnt_mountp, sizeof(pHandle->pszMountPoint) - 1); + + fclose (pMountTab); + return pHandle; + } + } + + fclose (pMountTab); + osl_freeVolumeDeviceHandleImpl (pHandle); + return NULL; +} + +static oslFileError osl_mountFloppy(oslVolumeDeviceHandle hFloppy) +{ + FILE* pMountTab; + struct mnttab aMountEnt; + oslVolumeDeviceHandleImpl* pHandle = (oslVolumeDeviceHandleImpl*) hFloppy; + + int nRet=0; + sal_Char pszCmd[512] = ""; + + if ( pHandle == 0 ) + return osl_File_E_INVAL; + + /* FIXME: don't know what this is good for */ + if ( pHandle->ident[0] != 'O' || pHandle->ident[1] != 'V' || pHandle->ident[2] != 'D' || pHandle->ident[3] != 'H' ) + return osl_File_E_INVAL; + + snprintf(pszCmd, sizeof(pszCmd), "eject -q %s > /dev/null 2>&1", pHandle->pszDevice); + + nRet = system( pszCmd ); + + switch ( WEXITSTATUS(nRet) ) + { + case 0: + { + /* lookup the device in mount tab again */ + if ((pMountTab = fopen (MOUNTTAB, "r")) == NULL) + return osl_File_E_BUSY; + + while (getmntent(pMountTab, &aMountEnt) == 0) + { + const char *pMountPoint = aMountEnt.mnt_mountp; + const char *pDevice = aMountEnt.mnt_special; + if ( 0 == strncmp( pHandle->pszDevice, aMountEnt.mnt_special, strlen(pHandle->pszDevice) ) ) + { + memset(pHandle->pszMountPoint, 0, sizeof(pHandle->pszMountPoint)); + strncpy (pHandle->pszMountPoint, aMountEnt.mnt_mountp, sizeof(pHandle->pszMountPoint) - 1); + + fclose (pMountTab); + return osl_File_E_None; + } + } + + fclose (pMountTab); + return osl_File_E_BUSY; + } + //break; // break not necessary here, see return statements before + + case 1: + return osl_File_E_BUSY; + + default: + break; + } + + return osl_File_E_BUSY; +} + +static oslFileError osl_unmountFloppy(oslVolumeDeviceHandle hFloppy) +{ +// FILE* pMountTab; +// struct mnttab aMountEnt; + oslVolumeDeviceHandleImpl* pHandle = (oslVolumeDeviceHandleImpl*) hFloppy; + + int nRet=0; + sal_Char pszCmd[512] = ""; + + if ( pHandle == 0 ) + return osl_File_E_INVAL; + + /* FIXME: don't know what this is good for */ + if ( pHandle->ident[0] != 'O' || pHandle->ident[1] != 'V' || pHandle->ident[2] != 'D' || pHandle->ident[3] != 'H' ) + return osl_File_E_INVAL; + + snprintf(pszCmd, sizeof(pszCmd), "eject %s > /dev/null 2>&1", pHandle->pszDevice); + + nRet = system( pszCmd ); + + switch ( WEXITSTATUS(nRet) ) + { + case 0: + { + FILE* pMountTab; + struct mnttab aMountEnt; + + /* lookup if device is still in mount tab */ + if ((pMountTab = fopen (MOUNTTAB, "r")) == NULL) + return osl_File_E_BUSY; + + while (getmntent(pMountTab, &aMountEnt) == 0) + { + const char *pMountPoint = aMountEnt.mnt_mountp; + const char *pDevice = aMountEnt.mnt_special; + if ( 0 == strncmp( pHandle->pszDevice, aMountEnt.mnt_special, strlen(pHandle->pszDevice) ) ) + { + fclose (pMountTab); + return osl_File_E_BUSY; + } + } + + fclose (pMountTab); + pHandle->pszMountPoint[0] = 0; + return osl_File_E_None; + } + + //break; //break not necessary, see return statements before + + case 1: + return osl_File_E_NODEV; + + case 4: + pHandle->pszMountPoint[0] = 0; + return osl_File_E_None; + + default: + break; + } + + return osl_File_E_BUSY; +} + +#endif /* SOLARIS */ + +/****************************************************************************** + * + * LINUX FLOPPY FUNCTIONS + * + *****************************************************************************/ + +#if defined(LINUX) +static oslVolumeDeviceHandle +osl_isFloppyDrive (const sal_Char* pszPath) +{ + oslVolumeDeviceHandleImpl* pItem = osl_newVolumeDeviceHandleImpl(); + if (osl_getFloppyMountEntry(pszPath, pItem)) + return (oslVolumeDeviceHandle) pItem; + + osl_freeVolumeDeviceHandleImpl (pItem); + return 0; +} +#endif /* LINUX */ + +#if defined(LINUX) +static oslFileError osl_mountFloppy(oslVolumeDeviceHandle hFloppy) +{ + sal_Bool bRet = sal_False; + oslVolumeDeviceHandleImpl* pItem=0; + int nRet; + sal_Char pszCmd[PATH_MAX]; + const sal_Char* pszMountProg = "mount"; + sal_Char* pszSuDo = 0; + sal_Char* pszTmp = 0; + + pszCmd[0] = '\0'; + +#ifdef TRACE_OSL_FILE + fprintf(stderr,"In osl_mountFloppy\n"); +#endif + + pItem = (oslVolumeDeviceHandleImpl*) hFloppy; + + if ( pItem == 0 ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_mountFloppy [pItem == 0]\n"); +#endif + + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_mountFloppy [invalid handle]\n"); +#endif + return osl_File_E_INVAL; + } + + bRet = osl_isFloppyMounted(pItem); + if ( bRet == sal_True ) + { +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"detected mounted floppy at '%s'\n",pItem->pszMountPoint); +#endif + return osl_File_E_BUSY; + } + + /* mfe: we can't use the mount(2) system call!!! */ + /* even if we are root */ + /* since mtab is not updated!!! */ + /* but we need it to be updated */ + /* some "magic" must be done */ + +/* nRet = mount(pItem->pszDevice,pItem->pszMountPoint,0,0,0); */ +/* if ( nRet != 0 ) */ +/* { */ +/* nRet=errno; */ +/* #ifdef DEBUG_OSL_FILE */ +/* perror("mount"); */ +/* #endif */ +/* } */ + + pszTmp = getenv("SAL_MOUNT_MOUNTPROG"); + if ( pszTmp != 0 ) + { + pszMountProg=pszTmp; + } + + pszTmp=getenv("SAL_MOUNT_SU_DO"); + if ( pszTmp != 0 ) + { + pszSuDo=pszTmp; + } + + if ( pszSuDo != 0 ) + { + snprintf(pszCmd, sizeof(pszCmd), "%s %s %s %s",pszSuDo,pszMountProg,pItem->pszDevice,pItem->pszMountPoint); + } + else + { + snprintf(pszCmd, sizeof(pszCmd), "%s %s",pszMountProg,pItem->pszMountPoint); + } + + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"executing '%s'\n",pszCmd); +#endif + + nRet = system(pszCmd); + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"call returned '%i'\n",nRet); + fprintf(stderr,"exit status is '%i'\n", WEXITSTATUS(nRet)); +#endif + + + switch ( WEXITSTATUS(nRet) ) + { + case 0: + nRet=0; + break; + + case 2: + nRet=EPERM; + break; + + case 4: + nRet=ENOENT; + break; + + case 8: + nRet=EINTR; + break; + + case 16: + nRet=EPERM; + break; + + case 32: + nRet=EBUSY; + break; + + case 64: + nRet=EAGAIN; + break; + + default: + nRet=EBUSY; + break; + } + + return ((0 == nRet) ? oslTranslateFileError(OSL_FET_SUCCESS, nRet) : oslTranslateFileError(OSL_FET_ERROR, nRet)); +} +#endif /* LINUX */ + + +#if defined(LINUX) +static oslFileError osl_unmountFloppy(oslVolumeDeviceHandle hFloppy) +{ + oslVolumeDeviceHandleImpl* pItem=0; + int nRet=0; + sal_Char pszCmd[PATH_MAX]; + sal_Char* pszTmp = 0; + sal_Char* pszSuDo = 0; + const sal_Char* pszUmountProg = "umount"; + + pszCmd[0] = '\0'; + +#ifdef TRACE_OSL_FILE + fprintf(stderr,"In osl_unmountFloppy\n"); +#endif + + pItem = (oslVolumeDeviceHandleImpl*) hFloppy; + + if ( pItem == 0 ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_unmountFloppy [pItem==0]\n"); +#endif + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_unmountFloppy [invalid handle]\n"); +#endif + return osl_File_E_INVAL; + } + + /* mfe: we can't use the umount(2) system call!!! */ + /* even if we are root */ + /* since mtab is not updated!!! */ + /* but we need it to be updated */ + /* some "magic" must be done */ + +/* nRet=umount(pItem->pszDevice); */ +/* if ( nRet != 0 ) */ +/* { */ +/* nRet = errno; */ + +/* #ifdef DEBUG_OSL_FILE */ +/* perror("mount"); */ +/* #endif */ +/* } */ + + + pszTmp = getenv("SAL_MOUNT_UMOUNTPROG"); + if ( pszTmp != 0 ) + { + pszUmountProg=pszTmp; + } + + pszTmp = getenv("SAL_MOUNT_SU_DO"); + if ( pszTmp != 0 ) + { + pszSuDo=pszTmp; + } + + if ( pszSuDo != 0 ) + { + snprintf(pszCmd, sizeof(pszCmd), "%s %s %s",pszSuDo,pszUmountProg,pItem->pszMountPoint); + } + else + { + snprintf(pszCmd, sizeof(pszCmd), "%s %s",pszUmountProg,pItem->pszMountPoint); + } + + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"executing '%s'\n",pszCmd); +#endif + + nRet = system(pszCmd); + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"call returned '%i'\n",nRet); + fprintf(stderr,"exit status is '%i'\n", WEXITSTATUS(nRet)); +#endif + + switch ( WEXITSTATUS(nRet) ) + { + case 0: + nRet=0; + break; + + default: + nRet=EBUSY; + break; + } + +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_unmountFloppy [ok]\n"); +#endif + + return ((0 == nRet) ? oslTranslateFileError(OSL_FET_SUCCESS, nRet) : oslTranslateFileError(OSL_FET_ERROR, nRet)); + +/* return osl_File_E_None;*/ +} + +#endif /* LINUX */ + +#if defined(LINUX) +static sal_Bool +osl_getFloppyMountEntry(const sal_Char* pszPath, oslVolumeDeviceHandleImpl* pItem) +{ + struct mntent* pMountEnt; + FILE* pMountTab; + + pMountTab = setmntent (MOUNTTAB, "r"); + if (pMountTab == 0) + return sal_False; + + while ((pMountEnt = getmntent(pMountTab)) != 0) + { + if ( strncmp(pMountEnt->mnt_dir, pszPath, strlen(pMountEnt->mnt_dir)) == 0 + && strncmp(pMountEnt->mnt_fsname, "/dev/fd", strlen("/dev/fd")) == 0) + { + memset(pItem->pszMountPoint, 0, sizeof(pItem->pszMountPoint)); + strncpy(pItem->pszMountPoint, pMountEnt->mnt_dir, sizeof(pItem->pszMountPoint) - 1); + + memset(pItem->pszFilePath, 0, sizeof(pItem->pszFilePath)); + strncpy(pItem->pszFilePath, pMountEnt->mnt_dir, sizeof(pItem->pszFilePath) - 1); + + memset(pItem->pszDevice, 0, sizeof(pItem->pszDevice)); + strncpy(pItem->pszDevice, pMountEnt->mnt_fsname, sizeof(pItem->pszDevice) - 1); + + endmntent (pMountTab); + return sal_True; + } + } + + endmntent (pMountTab); + return sal_False; +} +#endif /* LINUX */ + +#if defined(LINUX) +static sal_Bool +osl_isFloppyMounted (oslVolumeDeviceHandleImpl* pDevice) +{ + oslVolumeDeviceHandleImpl aItem; + + if ( osl_getFloppyMountEntry (pDevice->pszMountPoint, &aItem) + && strcmp (aItem.pszMountPoint, pDevice->pszMountPoint) == 0 + && strcmp (aItem.pszDevice, pDevice->pszDevice) == 0) + { + return sal_True; + } + return sal_False; +} +#endif /* LINUX */ + +/* NetBSD floppy functions have to be added here. Until we have done that, + * we use the MACOSX definitions for nonexistent floppy. + * */ + +/****************************************************************************** + * + * MAC OS X FLOPPY FUNCTIONS + * + *****************************************************************************/ + +#if (defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) +static oslVolumeDeviceHandle osl_isFloppyDrive(const sal_Char* pszPath) +{ + return NULL; +} +#endif /* MACOSX */ + +#if ( defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) +static oslFileError osl_mountFloppy(oslVolumeDeviceHandle hFloppy) +{ + return osl_File_E_BUSY; +} +#endif /* MACOSX */ + +#if ( defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) +static oslFileError osl_unmountFloppy(oslVolumeDeviceHandle hFloppy) +{ + return osl_File_E_BUSY; +} +#endif /* MACOSX */ + +#if ( defined(NETBSD) || defined(FREEBSD) ) +static sal_Bool osl_getFloppyMountEntry(const sal_Char* pszPath, oslVolumeDeviceHandleImpl* pItem) +{ + return sal_False; +} +#endif /* NETBSD || FREEBSD */ + +#if ( defined(NETBSD) || defined(FREEBSD) ) +static sal_Bool osl_isFloppyMounted(oslVolumeDeviceHandleImpl* pDevice) +{ + return sal_False; +} +#endif /* NETBSD || FREEBSD */ + + +#ifdef DEBUG_OSL_FILE +static void osl_printFloppyHandle(oslVolumeDeviceHandleImpl* pItem) +{ + if (pItem == 0 ) + { + fprintf(stderr,"NULL Handle\n"); + return; + } + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Invalid Handle]\n"); +#endif + return; + } + + + fprintf(stderr,"MountPoint : '%s'\n",pItem->pszMountPoint); + fprintf(stderr,"FilePath : '%s'\n",pItem->pszFilePath); + fprintf(stderr,"Device : '%s'\n",pItem->pszDevice); + + return; +} +#endif diff --git a/sal/osl/unx/interlck.c b/sal/osl/unx/interlck.c new file mode 100644 index 000000000000..0342cdd983b4 --- /dev/null +++ b/sal/osl/unx/interlck.c @@ -0,0 +1,170 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/interlck.h> +#include <osl/diagnose.h> + +#if ( defined ( SOLARIS ) || defined ( NETBSD ) ) && defined ( SPARC ) +#error please use asm/interlck_sparc.s +#elif defined ( SOLARIS) && defined ( X86 ) +#error please use asm/interlck_x86.s +#elif defined ( GCC ) && ( defined ( X86 ) || defined ( X86_64 ) ) +/* That's possible on x86-64 too since oslInterlockedCount is a sal_Int32 */ + +extern int osl_isSingleCPU; + +/*****************************************************************************/ +/* osl_incrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount) +{ + register oslInterlockedCount nCount asm("%eax"); + + nCount = 1; + + if ( osl_isSingleCPU ) { + __asm__ __volatile__ ( + "xaddl %0, %1\n\t" + : "+r" (nCount), "+m" (*pCount) + : /* nothing */ + : "memory"); + } + else { + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %1\n\t" + : "+r" (nCount), "+m" (*pCount) + : /* nothing */ + : "memory"); + } + + return ++nCount; +} + +oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount) +{ + register oslInterlockedCount nCount asm("%eax"); + + nCount = -1; + + if ( osl_isSingleCPU ) { + __asm__ __volatile__ ( + "xaddl %0, %1\n\t" + : "+r" (nCount), "+m" (*pCount) + : /* nothing */ + : "memory"); + } + else { + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %1\n\t" + : "+r" (nCount), "+m" (*pCount) + : /* nothing */ + : "memory"); + } + + return --nCount; +} + +#elif defined ( GCC ) && defined ( POWERPC ) + +/*****************************************************************************/ +/* osl_incrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount) +{ + /* "addi" doesn't work with r0 as second parameter */ + register oslInterlockedCount nCount __asm__ ("r4"); + + __asm__ __volatile__ ( + "1: lwarx %0,0,%2\n\t" + " addi %0,%0,1\n\t" + " stwcx. %0,0,%2\n\t" + " bne- 1b\n\t" + " isync" + : "=&r" (nCount), "=m" (*pCount) + : "r" (pCount) + : "memory"); + + return nCount; +} + +oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount) +{ + /* "subi" doesn't work with r0 as second parameter */ + register oslInterlockedCount nCount __asm__ ("r4"); + + __asm__ __volatile__ ( + "1: lwarx %0,0,%2\n\t" + " subi %0,%0,1\n\t" + " stwcx. %0,0,%2\n\t" + " bne- 1b\n\t" + " isync" + : "=&r" (nCount), "=m" (*pCount) + : "r" (pCount) + : "memory"); + + return nCount; +} + +#else +/* use only if nothing else works, expensive due to single mutex for all reference counts */ + +static pthread_mutex_t InterLock = PTHREAD_MUTEX_INITIALIZER; + +/*****************************************************************************/ +/* osl_incrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount) +{ + oslInterlockedCount Count; + + pthread_mutex_lock(&InterLock); + Count = ++(*pCount); + pthread_mutex_unlock(&InterLock); + + return (Count); +} + +/*****************************************************************************/ +/* osl_decrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount) +{ + oslInterlockedCount Count; + + pthread_mutex_lock(&InterLock); + Count = --(*pCount); + pthread_mutex_unlock(&InterLock); + + return (Count); +} + +#endif /* default */ diff --git a/sal/osl/unx/makefile.mk b/sal/osl/unx/makefile.mk new file mode 100644 index 000000000000..1dd47fb4d19b --- /dev/null +++ b/sal/osl/unx/makefile.mk @@ -0,0 +1,189 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=sal +.IF "$(WORK_STAMP)"=="MIX364" +TARGET=cppsal +.ELSE +TARGET=cpposl +.ENDIF +USE_LDUMP2=TRUE + +PROJECTPCH4DLL=TRUE +PROJECTPCH=cont_pch +PROJECTPCHSOURCE=cont_pch + +TARGETTYPE=CUI + + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +CFLAGS+= $(LFS_CFLAGS) +CXXFLAGS+= $(LFS_CFLAGS) + +# --- Files -------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/conditn.obj \ + $(SLO)$/diagnose.obj \ + $(SLO)$/semaphor.obj \ + $(SLO)$/socket.obj \ + $(SLO)$/interlck.obj \ + $(SLO)$/mutex.obj \ + $(SLO)$/nlsupport.obj \ + $(SLO)$/thread.obj \ + $(SLO)$/module.obj \ + $(SLO)$/process.obj \ + $(SLO)$/security.obj \ + $(SLO)$/profile.obj \ + $(SLO)$/time.obj \ + $(SLO)$/signal.obj \ + $(SLO)$/pipe.obj \ + $(SLO)$/system.obj \ + $(SLO)$/util.obj \ + $(SLO)$/tempfile.obj\ + $(SLO)$/file.obj \ + $(SLO)$/file_misc.obj\ + $(SLO)$/file_url.obj\ + $(SLO)$/file_error_transl.obj\ + $(SLO)$/file_path_helper.obj\ + $(SLO)$/file_stat.obj \ + $(SLO)$/file_volume.obj \ + $(SLO)$/uunxapi.obj\ + $(SLO)$/process_impl.obj\ + $(SLO)$/salinit.obj + + +#.IF "$(UPDATER)"=="YES" +OBJFILES= $(OBJ)$/conditn.obj \ + $(OBJ)$/diagnose.obj \ + $(OBJ)$/semaphor.obj \ + $(OBJ)$/socket.obj \ + $(OBJ)$/interlck.obj \ + $(OBJ)$/mutex.obj \ + $(OBJ)$/nlsupport.obj \ + $(OBJ)$/thread.obj \ + $(OBJ)$/module.obj \ + $(OBJ)$/process.obj \ + $(OBJ)$/security.obj \ + $(OBJ)$/profile.obj \ + $(OBJ)$/time.obj \ + $(OBJ)$/signal.obj \ + $(OBJ)$/pipe.obj \ + $(OBJ)$/system.obj \ + $(OBJ)$/util.obj \ + $(OBJ)$/tempfile.obj\ + $(OBJ)$/file.obj \ + $(OBJ)$/file_misc.obj\ + $(OBJ)$/file_url.obj\ + $(OBJ)$/file_error_transl.obj\ + $(OBJ)$/file_path_helper.obj\ + $(OBJ)$/file_stat.obj \ + $(OBJ)$/file_volume.obj \ + $(OBJ)$/uunxapi.obj\ + $(OBJ)$/process_impl.obj\ + $(OBJ)$/salinit.obj + +#.ENDIF + +.IF "$(OS)"=="MACOSX" +SLOFILES += $(SLO)$/osxlocale.obj +.ENDIF + +.IF "$(OS)"=="SOLARIS" || "$(OS)"=="FREEBSD" || "$(OS)"=="NETBSD" || "$(OS)$(CPU)"=="LINUXS" || "$(OS)"=="MACOSX" +SLOFILES += $(SLO)$/backtrace.obj +OBJFILES += $(OBJ)$/backtrace.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.IF "$(COM)"=="C50" +APP1STDLIBS+=-lC +.ENDIF + +.IF "$(OS)" == "LINUX" +.IF "$(PAM)" == "NO" +CFLAGS+=-DNOPAM +.IF "$(NEW_SHADOW_API)" == "YES" +CFLAGS+=-DNEW_SHADOW_API +.ENDIF +.ENDIF +.IF "$(PAM_LINK)" == "YES" +CFLAGS+=-DPAM_LINK +.ENDIF +.IF "$(CRYPT_LINK)" == "YES" +CFLAGS+=-DCRYPT_LINK +.ENDIF +.ENDIF + +.IF "$(ENABLE_CRASHDUMP)" != "" || "$(PRODUCT)" == "" +CFLAGS+=-DSAL_ENABLE_CRASH_REPORT +.ENDIF + +.INCLUDE : target.mk + +.IF "$(OS)$(CPU)"=="SOLARISU" || "$(OS)$(CPU)"=="SOLARISS" || "$(OS)$(CPU)"=="NETBSDS" || "$(OS)$(CPU)"=="LINUXS" + +$(SLO)$/interlck.obj: $(SLO)$/interlck.o + touch $(SLO)$/interlck.obj + +$(OBJ)$/interlck.obj: $(OBJ)$/interlck.o + touch $(OBJ)$/interlck.obj + +$(SLO)$/interlck.o: $(MISC)$/interlck_sparc.s + $(ASM) $(AFLAGS) -o $@ $< + +$(OBJ)$/interlck.o: $(MISC)$/interlck_sparc.s + $(ASM) $(AFLAGS) -o $@ $< + +$(MISC)$/interlck_sparc.s: asm/interlck_sparc.s + tr -d "\015" < $< > $@ + +.ENDIF + +.IF "$(OS)$(CPU)"=="SOLARISI" + +$(SLO)$/interlck.obj: $(SLO)$/interlck.o + touch $(SLO)$/interlck.obj + +$(OBJ)$/interlck.obj: $(OBJ)$/interlck.o + touch $(OBJ)$/interlck.obj + +$(SLO)$/interlck.o: $(MISC)$/interlck_x86.s + $(ASM) $(AFLAGS) -o $@ $< + +$(OBJ)$/interlck.o: $(MISC)$/interlck_x86.s + $(ASM) $(AFLAGS) -o $@ $< + +$(MISC)$/interlck_x86.s: asm/interlck_x86.s + tr -d "\015" < $< > $@ + +.ENDIF diff --git a/sal/osl/unx/module.c b/sal/osl/unx/module.c new file mode 100644 index 000000000000..8f8f76a8656c --- /dev/null +++ b/sal/osl/unx/module.c @@ -0,0 +1,242 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <sal/types.h> +#include <osl/diagnose.h> +#include <osl/module.h> +#include <osl/thread.h> +#include <osl/process.h> +#include <osl/file.h> + +#include "system.h" + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +/* implemented in file.c */ +extern int UnicodeToText(char *, size_t, const sal_Unicode *, sal_Int32); + +oslModule SAL_CALL osl_psz_loadModule(const sal_Char *pszModuleName, sal_Int32 nRtldMode); + +/*****************************************************************************/ +/* osl_loadModule */ +/*****************************************************************************/ + +oslModule SAL_CALL osl_loadModule(rtl_uString *ustrModuleName, sal_Int32 nRtldMode) +{ + oslModule pModule=0; + rtl_uString* ustrTmp = NULL; + + OSL_ENSURE(ustrModuleName,"osl_loadModule : string is not valid"); + + /* ensure ustrTmp hold valid string */ + if (osl_File_E_None != osl_getSystemPathFromFileURL(ustrModuleName, &ustrTmp)) + rtl_uString_assign(&ustrTmp, ustrModuleName); + + if (ustrTmp) + { + char buffer[PATH_MAX]; + + if (UnicodeToText(buffer, PATH_MAX, ustrTmp->buffer, ustrTmp->length)) + pModule = osl_psz_loadModule(buffer, nRtldMode); + rtl_uString_release(ustrTmp); + } + + return pModule; +} + +/*****************************************************************************/ +/* osl_psz_loadModule */ +/*****************************************************************************/ + +oslModule SAL_CALL osl_psz_loadModule(const sal_Char *pszModuleName, sal_Int32 nRtldMode) +{ + OSL_ASSERT( + (nRtldMode & SAL_LOADMODULE_LAZY) == 0 || + (nRtldMode & SAL_LOADMODULE_NOW) == 0); /* only either LAZY or NOW */ + if (pszModuleName) + { +#ifndef NO_DL_FUNCTIONS + int rtld_mode = + ((nRtldMode & SAL_LOADMODULE_NOW) ? RTLD_NOW : RTLD_LAZY) | + ((nRtldMode & SAL_LOADMODULE_GLOBAL) ? RTLD_GLOBAL : RTLD_LOCAL); + void* pLib = dlopen(pszModuleName, rtld_mode); + +#if OSL_DEBUG_LEVEL > 1 + if (pLib == 0) + OSL_TRACE("Error osl_loadModule: %s\n", dlerror()); +#endif /* OSL_DEBUG_LEVEL */ + + return ((oslModule)(pLib)); + +#else /* NO_DL_FUNCTIONS */ + printf("No DL Functions\n"); +#endif /* NO_DL_FUNCTIONS */ + } + return NULL; +} + +/*****************************************************************************/ +/* osl_getModuleHandle */ +/*****************************************************************************/ + +sal_Bool SAL_CALL +osl_getModuleHandle(rtl_uString *pModuleName, oslModule *pResult) +{ + (void) pModuleName; /* avoid warning about unused parameter */ + *pResult = (oslModule) RTLD_DEFAULT; + return sal_True; +} + +/*****************************************************************************/ +/* osl_unloadModule */ +/*****************************************************************************/ +void SAL_CALL osl_unloadModule(oslModule hModule) +{ + if (hModule) + { +#ifndef NO_DL_FUNCTIONS + int nRet = dlclose(hModule); + +#if OSL_DEBUG_LEVEL > 1 + if (nRet != 0) + { + fprintf(stderr, "Error osl_unloadModule: %s\n", dlerror()); + } +#else + (void) nRet; +#endif /* if OSL_DEBUG_LEVEL */ + +#endif /* ifndef NO_DL_FUNCTIONS */ + } +} + +/*****************************************************************************/ +/* osl_getSymbol */ +/*****************************************************************************/ +void* SAL_CALL +osl_getSymbol(oslModule Module, rtl_uString* pSymbolName) +{ + return (void *) osl_getFunctionSymbol(Module, pSymbolName); +} + + +/*****************************************************************************/ +/* osl_getAsciiFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL +osl_getAsciiFunctionSymbol(oslModule Module, const sal_Char *pSymbol) +{ + void *fcnAddr = NULL; + +#ifndef NO_DL_FUNCTIONS + if (pSymbol) + { + fcnAddr = dlsym(Module, pSymbol); + + if (!fcnAddr) + OSL_TRACE("Error osl_getAsciiFunctionSymbol: %s\n", dlerror()); + } +#endif + + return (oslGenericFunction) fcnAddr; +} + +/*****************************************************************************/ +/* osl_getFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL +osl_getFunctionSymbol(oslModule module, rtl_uString *puFunctionSymbolName) +{ + oslGenericFunction pSymbol = NULL; + + if( puFunctionSymbolName ) + { + rtl_String* pSymbolName = NULL; + + rtl_uString2String( &pSymbolName, + rtl_uString_getStr(puFunctionSymbolName), + rtl_uString_getLength(puFunctionSymbolName), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( pSymbolName != NULL ) + { + pSymbol = osl_getAsciiFunctionSymbol(module, rtl_string_getStr(pSymbolName)); + rtl_string_release(pSymbolName); + } + } + + return pSymbol; +} + +/*****************************************************************************/ +/* osl_getModuleURLFromAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromAddress(void * addr, rtl_uString ** ppLibraryUrl) +{ + sal_Bool result = sal_False; + Dl_info dl_info; + + if ((result = dladdr(addr, &dl_info)) != 0) + { + rtl_uString * workDir = NULL; + osl_getProcessWorkingDir(&workDir); + if (workDir) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE("module.c::osl_getModuleURLFromAddress - %s\n", dl_info.dli_fname); +#endif + rtl_string2UString(ppLibraryUrl, + dl_info.dli_fname, + strlen(dl_info.dli_fname), + osl_getThreadTextEncoding(), + OSTRING_TO_OUSTRING_CVTFLAGS); + + OSL_ASSERT(*ppLibraryUrl != NULL); + osl_getFileURLFromSystemPath(*ppLibraryUrl, ppLibraryUrl); + osl_getAbsoluteFileURL(workDir, *ppLibraryUrl, ppLibraryUrl); + + rtl_uString_release(workDir); + result = sal_True; + } + else + { + result = sal_False; + } + } + return result; +} + +/*****************************************************************************/ +/* osl_getModuleURLFromFunctionAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress(oslGenericFunction addr, rtl_uString ** ppLibraryUrl) +{ + return osl_getModuleURLFromAddress((void*)addr, ppLibraryUrl); +} diff --git a/sal/osl/unx/mutex.c b/sal/osl/unx/mutex.c new file mode 100644 index 000000000000..2f47ba8791ad --- /dev/null +++ b/sal/osl/unx/mutex.c @@ -0,0 +1,221 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/mutex.h> +#include <osl/diagnose.h> + +#include <pthread.h> +#include <stdlib.h> + +#if defined LINUX /* bad hack */ +int pthread_mutexattr_setkind_np(pthread_mutexattr_t *, int); +#define pthread_mutexattr_settype pthread_mutexattr_setkind_np +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#endif + +/* + Implementation notes: + oslMutex hides a pointer to the oslMutexImpl structure, which + ist needed to manage recursive locks on a mutex. + +*/ + +typedef struct _oslMutexImpl +{ + pthread_mutex_t mutex; +} oslMutexImpl; + + +/*****************************************************************************/ +/* osl_createMutex */ +/*****************************************************************************/ +oslMutex SAL_CALL osl_createMutex() +{ + oslMutexImpl* pMutex = (oslMutexImpl*) malloc(sizeof(oslMutexImpl)); + pthread_mutexattr_t aMutexAttr; + int nRet=0; + + OSL_ASSERT(pMutex); + + if ( pMutex == 0 ) + { + return 0; + } + + pthread_mutexattr_init(&aMutexAttr); + + nRet = pthread_mutexattr_settype(&aMutexAttr, PTHREAD_MUTEX_RECURSIVE); + + nRet = pthread_mutex_init(&(pMutex->mutex), &aMutexAttr); + if ( nRet != 0 ) + { + OSL_TRACE("osl_createMutex : mutex init failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + + free(pMutex); + pMutex = 0; + } + + pthread_mutexattr_destroy(&aMutexAttr); + + return (oslMutex) pMutex; +} + +/*****************************************************************************/ +/* osl_destroyMutex */ +/*****************************************************************************/ +void SAL_CALL osl_destroyMutex(oslMutex Mutex) +{ + oslMutexImpl* pMutex = (oslMutexImpl*) Mutex; + + OSL_ASSERT(pMutex); + + if ( pMutex != 0 ) + { + int nRet=0; + + nRet = pthread_mutex_destroy(&(pMutex->mutex)); + if ( nRet != 0 ) + { + OSL_TRACE("osl_destroyMutex : mutex destroy failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + free(pMutex); + } + + return; +} + +/*****************************************************************************/ +/* osl_acquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireMutex(oslMutex Mutex) +{ + oslMutexImpl* pMutex = (oslMutexImpl*) Mutex; + + OSL_ASSERT(pMutex); + + if ( pMutex != 0 ) + { + int nRet=0; + + nRet = pthread_mutex_lock(&(pMutex->mutex)); + if ( nRet != 0 ) + { + OSL_TRACE("osl_acquireMutex : mutex lock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + return sal_True; + } + + /* not initialized */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_tryToAcquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireMutex(oslMutex Mutex) +{ + oslMutexImpl* pMutex = (oslMutexImpl*) Mutex; + + OSL_ASSERT(pMutex); + + if ( pMutex ) + { + int nRet = 0; + nRet = pthread_mutex_trylock(&(pMutex->mutex)); + if ( nRet != 0 ) + return sal_False; + + return sal_True; + } + + /* not initialized */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_releaseMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseMutex(oslMutex Mutex) +{ + oslMutexImpl* pMutex = (oslMutexImpl*) Mutex; + + OSL_ASSERT(pMutex); + + if ( pMutex ) + { + int nRet=0; + nRet = pthread_mutex_unlock(&(pMutex->mutex)); + if ( nRet != 0 ) + { + OSL_TRACE("osl_releaseMutex : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + return sal_True; + } + + /* not initialized */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_getGlobalMutex */ +/*****************************************************************************/ + +static oslMutexImpl globalMutexImpl; + +static void globalMutexInitImpl(void) { + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr) != 0 || + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) || + pthread_mutex_init(&globalMutexImpl.mutex, &attr) != 0 || + pthread_mutexattr_destroy(&attr) != 0) + { + abort(); + } +} + +oslMutex * SAL_CALL osl_getGlobalMutex() +{ + /* necessary to get a "oslMutex *" */ + static oslMutex globalMutex = (oslMutex) &globalMutexImpl; + + static pthread_once_t once = PTHREAD_ONCE_INIT; + if (pthread_once(&once, &globalMutexInitImpl) != 0) { + abort(); + } + + return &globalMutex; +} diff --git a/sal/osl/unx/nlsupport.c b/sal/osl/unx/nlsupport.c new file mode 100644 index 000000000000..c9f4fd18df21 --- /dev/null +++ b/sal/osl/unx/nlsupport.c @@ -0,0 +1,949 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <osl/nlsupport.h> +#include <osl/diagnose.h> +#include <osl/process.h> +#include <rtl/memory.h> + +#if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) || defined(MACOSX) +#include <pthread.h> +#ifndef MACOSX + #include <locale.h> + #include <langinfo.h> +#else +#include <osl/module.h> +#include <osl/thread.h> +#endif /* !MACOSX */ +#endif /* LINUX || SOLARIS || NETBSD || MACOSX */ + +#include <string.h> + +/***************************************************************************** + typedefs + *****************************************************************************/ + + +typedef struct { + const char *key; + const rtl_TextEncoding value; +} _pair; + + +/***************************************************************************** + compare function for binary search + *****************************************************************************/ + +static int +_pair_compare (const char *key, const _pair *pair) +{ + int result = rtl_str_compareIgnoreAsciiCase( key, pair->key ); + return result; +} + +/***************************************************************************** + binary search on encoding tables + *****************************************************************************/ + +static const _pair* +_pair_search (const char *key, const _pair *base, unsigned int member ) +{ + unsigned int lower = 0; + unsigned int upper = member; + unsigned int current; + int comparison; + + /* check for validity of input */ + if ( (key == NULL) || (base == NULL) || (member == 0) ) + return NULL; + + /* binary search */ + while ( lower < upper ) + { + current = (lower + upper) / 2; + comparison = _pair_compare( key, base + current ); + if (comparison < 0) + upper = current; + else if (comparison > 0) + lower = current + 1; + else + return base + current; + } + + return NULL; +} + + +/***************************************************************************** + convert rtl_Locale to locale string + *****************************************************************************/ + +static char * _compose_locale( rtl_Locale * pLocale, char * buffer, size_t n ) +{ + /* check if a valid locale is specified */ + if( pLocale && pLocale->Language && + (pLocale->Language->length == 2 || pLocale->Language->length == 3) ) + { + size_t offset = 0; + + /* convert language code to ascii */ + { + rtl_String *pLanguage = NULL; + + rtl_uString2String( &pLanguage, + pLocale->Language->buffer, pLocale->Language->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( SAL_INT_CAST(sal_uInt32, pLanguage->length) < n ) + { + strcpy( buffer, pLanguage->buffer ); + offset = pLanguage->length; + } + + rtl_string_release( pLanguage ); + } + + /* convert country code to ascii */ + if( pLocale->Country && (pLocale->Country->length == 2) ) + { + rtl_String *pCountry = NULL; + + rtl_uString2String( &pCountry, + pLocale->Country->buffer, pLocale->Country->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( offset + pCountry->length + 1 < n ) + { + strcpy( buffer + offset++, "_" ); + strcpy( buffer + offset, pCountry->buffer ); + offset += pCountry->length; + } + + rtl_string_release( pCountry ); + } + + /* convert variant to ascii - check if there is enough space for the variant string */ + if( pLocale->Variant && pLocale->Variant->length && + ( SAL_INT_CAST(sal_uInt32, pLocale->Variant->length) < n - 6 ) ) + { + rtl_String *pVariant = NULL; + + rtl_uString2String( &pVariant, + pLocale->Variant->buffer, pLocale->Variant->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( offset + pVariant->length + 1 < n ) + { + strcpy( buffer + offset, pVariant->buffer ); + offset += pVariant->length; + } + + rtl_string_release( pVariant ); + } + + return buffer; + } + + return NULL; +} + +/***************************************************************************** + convert locale string to rtl_Locale + *****************************************************************************/ + +static rtl_Locale * _parse_locale( const char * locale ) +{ + static sal_Unicode c_locale[2] = { (sal_Unicode) 'C', 0 }; + + /* check if locale contains a valid string */ + if( locale ) + { + size_t len = strlen( locale ); + + if( len >= 2 ) + { + rtl_uString * pLanguage = NULL; + rtl_uString * pCountry = NULL; + rtl_uString * pVariant = NULL; + + size_t offset = 2; + + rtl_Locale * ret; + + /* language is a two or three letter code */ + if( (len > 3 && '_' == locale[3]) || (len == 3 && '_' != locale[2]) ) + offset = 3; + + /* convert language code to unicode */ + rtl_string2UString( &pLanguage, locale, offset, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pLanguage != NULL); + + /* convert country code to unicode */ + if( len >= offset+3 && '_' == locale[offset] ) + { + rtl_string2UString( &pCountry, locale + offset + 1, 2, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pCountry != NULL); + offset += 3; + } + + /* convert variant code to unicode - do not rely on "." as delimiter */ + if( len > offset ) { + rtl_string2UString( &pVariant, locale + offset, len - offset, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pVariant != NULL); + } + + ret = rtl_locale_register( pLanguage->buffer, pCountry ? pCountry->buffer : c_locale + 1, pVariant ? pVariant->buffer : c_locale + 1 ); + + if (pVariant) rtl_uString_release(pVariant); + if (pCountry) rtl_uString_release(pCountry); + if (pLanguage) rtl_uString_release(pLanguage); + + return ret; + } + else + return rtl_locale_register( c_locale, c_locale + 1, c_locale + 1 ); + } + + return NULL; +} + +#if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) + +/* + * This implementation of osl_getTextEncodingFromLocale maps + * from nl_langinfo(CODESET) to rtl_textencoding defines. + * nl_langinfo() is supported only on Linux, Solaris, + * >= NetBSD 1.6 and >= FreeBSD 4.4 + * + * This routine is SLOW because of the setlocale call, so + * grab the result and cache it. + * + * XXX this code has the usual mt problems aligned with setlocale() XXX + */ + +#ifdef LINUX +#if !defined(CODESET) +#define CODESET _NL_CTYPE_CODESET_NAME +#endif +#endif + +/* + * _nl_language_list[] is an array list of supported encodings. Because + * we are using a binary search, the list has to be in ascending order. + * We are comparing the encodings case insensitiv, so the list has + * to be completly upper- , or lowercase. + */ + +#if defined(SOLARIS) + +/* The values in the below list can be obtained with a script like + * #!/bin/sh + * for i in `locale -a`; do + * LC_ALL=$i locale -k code_set_name + * done + */ +const _pair _nl_language_list[] = { + { "5601", RTL_TEXTENCODING_EUC_KR }, /* ko_KR.EUC */ + { "646", RTL_TEXTENCODING_ISO_8859_1 }, /* fake: ASCII_US */ + { "ANSI-1251", RTL_TEXTENCODING_MS_1251 }, /* ru_RU.ANSI1251 */ + { "BIG5", RTL_TEXTENCODING_BIG5 }, /* zh_CN.BIG5 */ + { "BIG5-HKSCS", RTL_TEXTENCODING_BIG5_HKSCS }, /* zh_CN.BIG5HK */ + { "CNS11643", RTL_TEXTENCODING_EUC_TW }, /* zh_TW.EUC */ + { "EUCJP", RTL_TEXTENCODING_EUC_JP }, /* ja_JP.eucjp */ + { "GB18030", RTL_TEXTENCODING_GB_18030 }, /* zh_CN.GB18030 */ + { "GB2312", RTL_TEXTENCODING_GB_2312 }, /* zh_CN */ + { "GBK", RTL_TEXTENCODING_GBK }, /* zh_CN.GBK */ + { "ISO8859-1", RTL_TEXTENCODING_ISO_8859_1 }, + { "ISO8859-10", RTL_TEXTENCODING_ISO_8859_10 }, + { "ISO8859-13", RTL_TEXTENCODING_ISO_8859_13 }, /* lt_LT lv_LV */ + { "ISO8859-14", RTL_TEXTENCODING_ISO_8859_14 }, + { "ISO8859-15", RTL_TEXTENCODING_ISO_8859_15 }, + { "ISO8859-2", RTL_TEXTENCODING_ISO_8859_2 }, + { "ISO8859-3", RTL_TEXTENCODING_ISO_8859_3 }, + { "ISO8859-4", RTL_TEXTENCODING_ISO_8859_4 }, + { "ISO8859-5", RTL_TEXTENCODING_ISO_8859_5 }, + { "ISO8859-6", RTL_TEXTENCODING_ISO_8859_6 }, + { "ISO8859-7", RTL_TEXTENCODING_ISO_8859_7 }, + { "ISO8859-8", RTL_TEXTENCODING_ISO_8859_8 }, + { "ISO8859-9", RTL_TEXTENCODING_ISO_8859_9 }, + { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, + { "KOI8-U", RTL_TEXTENCODING_KOI8_U }, + { "PCK", RTL_TEXTENCODING_MS_932 }, + { "SUN_EU_GREEK", RTL_TEXTENCODING_ISO_8859_7 }, /* 8859-7 + Euro */ + { "TIS620.2533", RTL_TEXTENCODING_MS_874 }, /* th_TH.TIS620 */ + { "UTF-8", RTL_TEXTENCODING_UTF8 } +}; + +/* XXX MS-874 is an extension to tis620, so this is not + * really equivalent */ + +#elif defined(LINUX) || defined(NETBSD) + +const _pair _nl_language_list[] = { + { "ANSI_X3.110-1983", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-99 NAPLPS */ + { "ANSI_X3.4-1968", RTL_TEXTENCODING_ISO_8859_1 }, /* fake: ASCII_US */ + { "ASMO_449", RTL_TEXTENCODING_DONTKNOW }, /* ISO_9036 ARABIC7 */ + { "BALTIC", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-179 */ + { "BIG5", RTL_TEXTENCODING_BIG5 }, /* locale: zh_TW */ + { "BIG5-HKSCS", RTL_TEXTENCODING_BIG5_HKSCS }, /* locale: zh_CN.BIG5HK */ + { "BIG5HKSCS", RTL_TEXTENCODING_BIG5_HKSCS }, /* depricated */ + { "BS_4730", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-4 ISO646-GB */ + { "BS_VIEWDATA", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-47 */ + { "CP1250", RTL_TEXTENCODING_MS_1250 }, /* MS-EE */ + { "CP1251", RTL_TEXTENCODING_MS_1251 }, /* MS-CYRL */ + { "CP1252", RTL_TEXTENCODING_MS_1252 }, /* MS-ANSI */ + { "CP1253", RTL_TEXTENCODING_MS_1253 }, /* MS-GREEK */ + { "CP1254", RTL_TEXTENCODING_MS_1254 }, /* MS-TURK */ + { "CP1255", RTL_TEXTENCODING_MS_1255 }, /* MS-HEBR */ + { "CP1256", RTL_TEXTENCODING_MS_1256 }, /* MS-ARAB */ + { "CP1257", RTL_TEXTENCODING_MS_1257 }, /* WINBALTRIM */ + { "CSA_Z243.4-1985-1", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-121 */ + { "CSA_Z243.4-1985-2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-122 CSA7-2 */ + { "CSA_Z243.4-1985-GR", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-123 */ + { "CSN_369103", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-139 */ + { "CWI", RTL_TEXTENCODING_DONTKNOW }, /* CWI-2 CP-HU */ + { "DEC-MCS", RTL_TEXTENCODING_DONTKNOW }, /* DEC */ + { "DIN_66003", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-21 */ + { "DS_2089", RTL_TEXTENCODING_DONTKNOW }, /* DS2089 ISO646-DK */ + { "EBCDIC-AT-DE", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-AT-DE-A", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-CA-FR", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-DK-NO", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-DK-NO-A", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-ES", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-ES-A", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-ES-S", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-FI-SE", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-FI-SE-A", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-FR", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-IS-FRISS", RTL_TEXTENCODING_DONTKNOW }, /* FRISS */ + { "EBCDIC-IT", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-PT", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-UK", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-US", RTL_TEXTENCODING_DONTKNOW }, + { "ECMA-CYRILLIC", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-111 */ + { "ES", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-17 */ + { "ES2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-85 */ + { "EUC-JP", RTL_TEXTENCODING_EUC_JP }, /* locale: ja_JP.eucjp */ + { "EUC-KR", RTL_TEXTENCODING_EUC_KR }, /* locale: ko_KR.euckr */ + { "EUC-TW", RTL_TEXTENCODING_EUC_TW }, /* locale: zh_TW.euctw */ + { "GB18030", RTL_TEXTENCODING_GB_18030 }, /* locale: zh_CN.gb18030 */ + { "GB2312", RTL_TEXTENCODING_GB_2312 }, /* locale: zh_CN */ + { "GB_1988-80", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-57 */ + { "GBK", RTL_TEXTENCODING_GBK }, /* locale: zh_CN.GBK */ + { "GOST_19768-74", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-153 */ + { "GREEK-CCITT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-150 */ + { "GREEK7", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-88 */ + { "GREEK7-OLD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-18 */ + { "HP-ROMAN8", RTL_TEXTENCODING_DONTKNOW }, /* ROMAN8 R8 */ + { "IBM037", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-[US|CA|WT] */ + { "IBM038", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-INT CP038 */ + { "IBM1004", RTL_TEXTENCODING_DONTKNOW }, /* CP1004 OS2LATIN1 */ + { "IBM1026", RTL_TEXTENCODING_DONTKNOW }, /* CP1026 1026 */ + { "IBM1047", RTL_TEXTENCODING_DONTKNOW }, /* CP1047 1047 */ + { "IBM256", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-INT1 */ + { "IBM273", RTL_TEXTENCODING_DONTKNOW }, /* CP273 */ + { "IBM274", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-BE CP274 */ + { "IBM275", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-BR CP275 */ + { "IBM277", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-[DK|NO] */ + { "IBM278", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-[FISE]*/ + { "IBM280", RTL_TEXTENCODING_DONTKNOW }, /* CP280 EBCDIC-CP-IT*/ + { "IBM281", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-JP-E CP281 */ + { "IBM284", RTL_TEXTENCODING_DONTKNOW }, /* CP284 EBCDIC-CP-ES */ + { "IBM285", RTL_TEXTENCODING_DONTKNOW }, /* CP285 EBCDIC-CP-GB */ + { "IBM290", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-JP-KANA */ + { "IBM297", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-FR */ + { "IBM420", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-AR1 */ + { "IBM423", RTL_TEXTENCODING_DONTKNOW }, /* CP423 EBCDIC-CP-GR */ + { "IBM424", RTL_TEXTENCODING_DONTKNOW }, /* CP424 EBCDIC-CP-HE */ + { "IBM437", RTL_TEXTENCODING_IBM_437 }, /* CP437 437 */ + { "IBM500", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-[BE|CH] */ + { "IBM850", RTL_TEXTENCODING_IBM_850 }, /* CP850 850 */ + { "IBM851", RTL_TEXTENCODING_DONTKNOW }, /* CP851 851 */ + { "IBM852", RTL_TEXTENCODING_IBM_852 }, /* CP852 852 */ + { "IBM855", RTL_TEXTENCODING_IBM_855 }, /* CP855 855 */ + { "IBM857", RTL_TEXTENCODING_IBM_857 }, /* CP857 857 */ + { "IBM860", RTL_TEXTENCODING_IBM_860 }, /* CP860 860 */ + { "IBM861", RTL_TEXTENCODING_IBM_861 }, /* CP861 861 CP-IS */ + { "IBM862", RTL_TEXTENCODING_IBM_862 }, /* CP862 862 */ + { "IBM863", RTL_TEXTENCODING_IBM_863 }, /* CP863 863 */ + { "IBM864", RTL_TEXTENCODING_IBM_864 }, /* CP864 */ + { "IBM865", RTL_TEXTENCODING_IBM_865 }, /* CP865 865 */ + { "IBM866", RTL_TEXTENCODING_IBM_866 }, /* CP866 866 */ + { "IBM868", RTL_TEXTENCODING_DONTKNOW }, /* CP868 CP-AR */ + { "IBM869", RTL_TEXTENCODING_IBM_869 }, /* CP869 869 CP-GR */ + { "IBM870", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-[ROECE|YU] */ + { "IBM871", RTL_TEXTENCODING_DONTKNOW }, /* CP871 EBCDIC-CP-IS */ + { "IBM875", RTL_TEXTENCODING_DONTKNOW }, /* CP875 EBCDIC-GREEK */ + { "IBM880", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CYRILLIC */ + { "IBM891", RTL_TEXTENCODING_DONTKNOW }, /* CP891 */ + { "IBM903", RTL_TEXTENCODING_DONTKNOW }, /* CP903 */ + { "IBM904", RTL_TEXTENCODING_DONTKNOW }, /* CP904 904 */ + { "IBM905", RTL_TEXTENCODING_DONTKNOW }, /* CP905 EBCDIC-CP-TR */ + { "IBM918", RTL_TEXTENCODING_DONTKNOW }, /* CP918 EBCDIC-AR2 */ + { "IEC_P27-1", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-143 */ + { "INIS", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-49 */ + { "INIS-8", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-50 */ + { "INIS-CYRILLIC", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-51 */ + { "INVARIANT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-170 */ + { "ISO-8859-1", RTL_TEXTENCODING_ISO_8859_1 }, /* ISO-IR-100 CP819 */ + { "ISO-8859-10", RTL_TEXTENCODING_ISO_8859_10 }, /* ISO-IR-157 LATIN6 */ + { "ISO-8859-13", RTL_TEXTENCODING_ISO_8859_13 }, /* ISO-IR-179 LATIN7 */ + { "ISO-8859-14", RTL_TEXTENCODING_ISO_8859_14 }, /* LATIN8 L8 */ + { "ISO-8859-15", RTL_TEXTENCODING_ISO_8859_15 }, + { "ISO-8859-2", RTL_TEXTENCODING_ISO_8859_2 }, /* LATIN2 L2 */ + { "ISO-8859-3", RTL_TEXTENCODING_ISO_8859_3 }, /* LATIN3 L3 */ + { "ISO-8859-4", RTL_TEXTENCODING_ISO_8859_4 }, /* LATIN4 L4 */ + { "ISO-8859-5", RTL_TEXTENCODING_ISO_8859_5 }, /* CYRILLIC */ + { "ISO-8859-6", RTL_TEXTENCODING_ISO_8859_6 }, /* ECMA-114 ARABIC */ + { "ISO-8859-7", RTL_TEXTENCODING_ISO_8859_7 }, /* ECMA-118 GREEK8 */ + { "ISO-8859-8", RTL_TEXTENCODING_ISO_8859_8 }, /* ISO_8859-8 HEBREW */ + { "ISO-8859-9", RTL_TEXTENCODING_ISO_8859_9 }, /* ISO_8859-9 LATIN5 */ + { "ISO-IR-90", RTL_TEXTENCODING_DONTKNOW }, /* ISO_6937-2:1983 */ + { "ISO_10367-BOX", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-155 */ + { "ISO_2033-1983", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-98 E13B */ + { "ISO_5427", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-37 KOI-7 */ + { "ISO_5427-EXT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-54 */ + { "ISO_5428", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-55 */ + { "ISO_646.BASIC", RTL_TEXTENCODING_ASCII_US }, /* REF */ + { "ISO_646.IRV", RTL_TEXTENCODING_ASCII_US }, /* ISO-IR-2 IRV */ + { "ISO_646.IRV:1983", RTL_TEXTENCODING_ISO_8859_1 }, /* fake: ASCII_US, used for "C" locale*/ + { "ISO_6937", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-156 ISO6937*/ + { "ISO_6937-2-25", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-152 */ + { "ISO_6937-2-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-142 */ + { "ISO_8859-SUPP", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-154 */ + { "IT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-15 */ + { "JIS_C6220-1969-JP", RTL_TEXTENCODING_DONTKNOW }, /* KATAKANA X0201-7 */ + { "JIS_C6220-1969-RO", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-14 */ + { "JIS_C6229-1984-A", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-91 */ + { "JIS_C6229-1984-B", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-92 */ + { "JIS_C6229-1984-B-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-93 */ + { "JIS_C6229-1984-HAND", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-94 */ + { "JIS_C6229-1984-HAND-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-95 */ + { "JIS_C6229-1984-KANA", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-96 */ + { "JIS_X0201", RTL_TEXTENCODING_DONTKNOW }, /* X0201 */ + { "JUS_I.B1.002", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-141 */ + { "JUS_I.B1.003-MAC", RTL_TEXTENCODING_DONTKNOW }, /* MACEDONIAN */ + { "JUS_I.B1.003-SERB", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-146 SERBIAN */ + { "KOI-8", RTL_TEXTENCODING_DONTKNOW }, + { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, + { "KOI8-U", RTL_TEXTENCODING_KOI8_U }, + { "KSC5636", RTL_TEXTENCODING_DONTKNOW }, /* ISO646-KR */ + { "LATIN-GREEK", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-19 */ + { "LATIN-GREEK-1", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-27 */ + { "MAC-IS", RTL_TEXTENCODING_APPLE_ROMAN }, + { "MAC-UK", RTL_TEXTENCODING_APPLE_ROMAN }, + { "MACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN }, /* MAC */ + { "MSZ_7795.3", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-86 */ + { "NATS-DANO", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-9-1 */ + { "NATS-DANO-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-9-2 */ + { "NATS-SEFI", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-8-1 */ + { "NATS-SEFI-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-8-2 */ + { "NC_NC00-10", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-151 */ + { "NEXTSTEP", RTL_TEXTENCODING_DONTKNOW }, /* NEXT */ + { "NF_Z_62-010", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-69 */ + { "NF_Z_62-010_(1973)", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-25 */ + { "NS_4551-1", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-60 */ + { "NS_4551-2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-61 */ + { "PT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-16 */ + { "PT2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-84 */ + { "SAMI", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-158 */ + { "SEN_850200_B", RTL_TEXTENCODING_DONTKNOW }, /* ISO646-[FI|SE] */ + { "SEN_850200_C", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-11 */ + { "T.101-G2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-128 */ + { "T.61-7BIT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-102 */ + { "T.61-8BIT", RTL_TEXTENCODING_DONTKNOW }, /* T.61 ISO-IR-103 */ + { "TIS-620", RTL_TEXTENCODING_MS_874 }, /* locale: th_TH */ + { "UTF-8", RTL_TEXTENCODING_UTF8 }, /* ISO-10646/UTF-8 */ + { "VIDEOTEX-SUPPL", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-70 */ + { "WIN-SAMI-2", RTL_TEXTENCODING_DONTKNOW } /* WS2 */ +}; + +#elif defined(FREEBSD) + +const _pair _nl_language_list[] = { + { "ASCII", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "BIG5", RTL_TEXTENCODING_BIG5 }, /* China - Traditional Chinese */ + { "CP1251", RTL_TEXTENCODING_MS_1251 }, /* MS-CYRL */ + { "CP866", RTL_TEXTENCODING_IBM_866 }, /* CP866 866 */ + { "EUCCN", RTL_TEXTENCODING_EUC_CN }, /* China - Simplified Chinese */ + { "EUCJP", RTL_TEXTENCODING_EUC_JP }, /* Japan */ + { "EUCKR", RTL_TEXTENCODING_EUC_KR }, /* Korea */ + { "ISO8859-1", RTL_TEXTENCODING_ISO_8859_1 }, /* Western */ + { "ISO8859-15", RTL_TEXTENCODING_ISO_8859_15 }, /* Western Updated (w/Euro sign) */ + { "ISO8859-2", RTL_TEXTENCODING_ISO_8859_2 }, /* Central European */ + { "ISO8859-4", RTL_TEXTENCODING_ISO_8859_4 }, /* LATIN4 L4 */ + { "ISO8859-5", RTL_TEXTENCODING_ISO_8859_5 }, /* Cyrillic */ + { "ISO8859-7", RTL_TEXTENCODING_ISO_8859_7 }, /* Greek */ + { "ISO8859-9", RTL_TEXTENCODING_ISO_8859_9 }, /* Turkish */ + { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, /* KOI8-R */ + { "KOI8-U", RTL_TEXTENCODING_KOI8_U }, /* KOI8-U */ + { "SJIS", RTL_TEXTENCODING_SHIFT_JIS }, /* Japan */ + { "US-ASCII", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "UTF-8", RTL_TEXTENCODING_UTF8 } /* ISO-10646/UTF-8 */ +}; + +#elif defined(NETBSD) + +const _pair _nl_language_list[] = { + { "ASCII", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "BIG5", RTL_TEXTENCODING_BIG5 }, /* China - Traditional Chinese */ + { "CP1251", RTL_TEXTENCODING_MS_1251 }, /* MS-CYRL */ + { "CP866", RTL_TEXTENCODING_IBM_866 }, /* CP866 866 */ + { "CTEXT", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "EUCCN", RTL_TEXTENCODING_EUC_CN }, /* China - Simplified Chinese */ + { "EUCJP", RTL_TEXTENCODING_EUC_JP }, /* Japan */ + { "EUCKR", RTL_TEXTENCODING_EUC_KR }, /* Korea */ + { "EUCTW", RTL_TEXTENCODING_EUC_TW }, /* China - Traditional Chinese */ + { "ISO-2022-JP", RTL_TEXTENCODING_DONTKNOW }, /* */ + { "ISO-2022-JP-2", RTL_TEXTENCODING_DONTKNOW }, /* */ + { "ISO8859-1", RTL_TEXTENCODING_ISO_8859_1 }, /* Western */ + { "ISO8859-15", RTL_TEXTENCODING_ISO_8859_15 }, /* Western Updated (w/Euro sign) */ + { "ISO8859-2", RTL_TEXTENCODING_ISO_8859_2 }, /* Central European */ + { "ISO8859-4", RTL_TEXTENCODING_ISO_8859_4 }, /* LATIN4 L4 */ + { "ISO8859-5", RTL_TEXTENCODING_ISO_8859_5 }, /* Cyrillic */ + { "ISO8859-7", RTL_TEXTENCODING_ISO_8859_7 }, /* Greek */ + { "ISO8859-9", RTL_TEXTENCODING_ISO_8859_9 }, /* Turkish */ + { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, /* KOI8-R */ + { "KOI8-U", RTL_TEXTENCODING_KOI8_U }, /* KOI8-U */ + { "SJIS", RTL_TEXTENCODING_SHIFT_JIS }, /* Japan */ + { "US-ASCII", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "UTF-8", RTL_TEXTENCODING_UTF8 } /* ISO-10646/UTF-8 */ +}; + +#endif /* ifdef SOLARIS LINUX FREEBSD NETBSD */ + +static pthread_mutex_t aLocalMutex = PTHREAD_MUTEX_INITIALIZER; + +/***************************************************************************** + return the text encoding corresponding to the given locale + *****************************************************************************/ + +rtl_TextEncoding osl_getTextEncodingFromLocale( rtl_Locale * pLocale ) +{ + const _pair *language=0; + + char locale_buf[64] = ""; + char codeset_buf[64]; + + char *ctype_locale = 0; + char *codeset = 0; + + /* default to process locale if pLocale == NULL */ + if( NULL == pLocale ) + osl_getProcessLocale( &pLocale ); + + /* convert rtl_Locale to locale string */ + _compose_locale( pLocale, locale_buf, 64 ); + + /* basic thread safeness */ + pthread_mutex_lock( &aLocalMutex ); + + /* remember the charset as indicated by the LC_CTYPE locale */ + ctype_locale = setlocale( LC_CTYPE, NULL ); + + /* set the desired LC_CTYPE locale */ + if( NULL == setlocale( LC_CTYPE, locale_buf ) ) + { + pthread_mutex_unlock(&aLocalMutex); + return RTL_TEXTENCODING_DONTKNOW; + } + + /* get the charset as indicated by the LC_CTYPE locale */ +#if defined(NETBSD) && !defined(CODESET) + codeset = NULL; +#else + codeset = nl_langinfo( CODESET ); +#endif + + if ( codeset != NULL ) + { + /* get codeset into mt save memory */ + strncpy( codeset_buf, codeset, sizeof(codeset_buf) ); + codeset_buf[sizeof(codeset_buf) - 1] = 0; + codeset = codeset_buf; + } + + /* restore the original value of locale */ + if ( ctype_locale != NULL ) + setlocale( LC_CTYPE, ctype_locale ); + + pthread_mutex_unlock( &aLocalMutex ); + + /* search the codeset in our language list */ + if ( codeset != NULL ) + { + const unsigned int members = sizeof(_nl_language_list) / sizeof(_pair); + language = _pair_search (codeset, _nl_language_list, members); + } + + OSL_ASSERT( language && ( RTL_TEXTENCODING_DONTKNOW != language->value ) ); + + /* a matching item in our list provides a mapping from codeset to + * rtl-codeset */ + if ( language != NULL ) + return language->value; + + return RTL_TEXTENCODING_DONTKNOW; +} + +/***************************************************************************** + return the current process locale + *****************************************************************************/ + +void _imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + char * locale; + + /* basic thread safeness */ + pthread_mutex_lock( &aLocalMutex ); + + /* set the locale defined by the env vars */ + locale = setlocale( LC_CTYPE, "" ); + + /* fallback to the current locale */ + if( NULL == locale ) + locale = setlocale( LC_CTYPE, NULL ); + + /* return the LC_CTYPE locale */ + *ppLocale = _parse_locale( locale ); + + pthread_mutex_unlock( &aLocalMutex ); +} + +/***************************************************************************** + set the current process locale + *****************************************************************************/ + +int _imp_setProcessLocale( rtl_Locale * pLocale ) +{ + char locale_buf[64] = ""; + int ret = 0; + + /* convert rtl_Locale to locale string */ + _compose_locale( pLocale, locale_buf, 64 ); + + /* basic thread safeness */ + pthread_mutex_lock( &aLocalMutex ); + + /* try to set LC_ALL locale */ + if( NULL == setlocale( LC_ALL, locale_buf ) ) + ret = -1; + + pthread_mutex_unlock( &aLocalMutex ); + return ret; +} + +#else /* ifdef LINUX || SOLARIS || MACOSX || NETBSD */ + +/* + * This implementation of osl_getTextEncodingFromLocale maps + * from the ISO language codes. + */ + +const _pair _full_locale_list[] = { + { "ja_JP.eucJP", RTL_TEXTENCODING_EUC_JP }, + { "ja_JP.EUC", RTL_TEXTENCODING_EUC_JP }, + { "ko_KR.EUC", RTL_TEXTENCODING_EUC_KR }, + { "zh_CN.EUC", RTL_TEXTENCODING_EUC_CN }, + { "zh_TW.EUC", RTL_TEXTENCODING_EUC_TW } +}; + +const _pair _locale_extension_list[] = { + { "big5", RTL_TEXTENCODING_BIG5 }, + { "big5hk", RTL_TEXTENCODING_BIG5_HKSCS }, + { "gb18030", RTL_TEXTENCODING_GB_18030 }, + { "euc", RTL_TEXTENCODING_EUC_JP }, + { "iso8859-1", RTL_TEXTENCODING_ISO_8859_1 }, + { "iso8859-10", RTL_TEXTENCODING_ISO_8859_10 }, + { "iso8859-13", RTL_TEXTENCODING_ISO_8859_13 }, + { "iso8859-14", RTL_TEXTENCODING_ISO_8859_14 }, + { "iso8859-15", RTL_TEXTENCODING_ISO_8859_15 }, + { "iso8859-2", RTL_TEXTENCODING_ISO_8859_2 }, + { "iso8859-3", RTL_TEXTENCODING_ISO_8859_3 }, + { "iso8859-4", RTL_TEXTENCODING_ISO_8859_4 }, + { "iso8859-5", RTL_TEXTENCODING_ISO_8859_5 }, + { "iso8859-6", RTL_TEXTENCODING_ISO_8859_6 }, + { "iso8859-7", RTL_TEXTENCODING_ISO_8859_7 }, + { "iso8859-8", RTL_TEXTENCODING_ISO_8859_8 }, + { "iso8859-9", RTL_TEXTENCODING_ISO_8859_9 }, + { "koi8-r", RTL_TEXTENCODING_KOI8_R }, + { "koi8-u", RTL_TEXTENCODING_KOI8_U }, + { "pck", RTL_TEXTENCODING_MS_932 }, +#if (0) + { "sun_eu_greek", RTL_TEXTENCODING_DONTKNOW }, +#endif + { "utf-16", RTL_TEXTENCODING_UNICODE }, + { "utf-7", RTL_TEXTENCODING_UTF7 }, + { "utf-8", RTL_TEXTENCODING_UTF8 } +}; + +const _pair _iso_language_list[] = { + { "af", RTL_TEXTENCODING_ISO_8859_1 }, + { "ar", RTL_TEXTENCODING_ISO_8859_6 }, + { "az", RTL_TEXTENCODING_ISO_8859_9 }, + { "be", RTL_TEXTENCODING_ISO_8859_5 }, + { "bg", RTL_TEXTENCODING_ISO_8859_5 }, + { "ca", RTL_TEXTENCODING_ISO_8859_1 }, + { "cs", RTL_TEXTENCODING_ISO_8859_2 }, + { "da", RTL_TEXTENCODING_ISO_8859_1 }, + { "de", RTL_TEXTENCODING_ISO_8859_1 }, + { "el", RTL_TEXTENCODING_ISO_8859_7 }, + { "en", RTL_TEXTENCODING_ISO_8859_1 }, + { "es", RTL_TEXTENCODING_ISO_8859_1 }, + { "et", RTL_TEXTENCODING_ISO_8859_4 }, + { "eu", RTL_TEXTENCODING_ISO_8859_1 }, + { "fa", RTL_TEXTENCODING_ISO_8859_6 }, + { "fi", RTL_TEXTENCODING_ISO_8859_1 }, + { "fo", RTL_TEXTENCODING_ISO_8859_1 }, + { "fr", RTL_TEXTENCODING_ISO_8859_1 }, + { "gr", RTL_TEXTENCODING_ISO_8859_7 }, + { "he", RTL_TEXTENCODING_ISO_8859_8 }, + { "hi", RTL_TEXTENCODING_DONTKNOW }, + { "hr", RTL_TEXTENCODING_ISO_8859_2 }, + { "hu", RTL_TEXTENCODING_ISO_8859_2 }, + { "hy", RTL_TEXTENCODING_DONTKNOW }, + { "id", RTL_TEXTENCODING_ISO_8859_1 }, + { "is", RTL_TEXTENCODING_ISO_8859_1 }, + { "it", RTL_TEXTENCODING_ISO_8859_1 }, + { "iw", RTL_TEXTENCODING_ISO_8859_8 }, + { "ja", RTL_TEXTENCODING_EUC_JP }, + { "ka", RTL_TEXTENCODING_DONTKNOW }, + { "kk", RTL_TEXTENCODING_ISO_8859_5 }, + { "ko", RTL_TEXTENCODING_EUC_KR }, + { "lt", RTL_TEXTENCODING_ISO_8859_4 }, + { "lv", RTL_TEXTENCODING_ISO_8859_4 }, + { "mk", RTL_TEXTENCODING_ISO_8859_5 }, + { "mr", RTL_TEXTENCODING_DONTKNOW }, + { "ms", RTL_TEXTENCODING_ISO_8859_1 }, + { "nl", RTL_TEXTENCODING_ISO_8859_1 }, + { "no", RTL_TEXTENCODING_ISO_8859_1 }, + { "pl", RTL_TEXTENCODING_ISO_8859_2 }, + { "pt", RTL_TEXTENCODING_ISO_8859_1 }, + { "ro", RTL_TEXTENCODING_ISO_8859_2 }, + { "ru", RTL_TEXTENCODING_ISO_8859_5 }, + { "sa", RTL_TEXTENCODING_DONTKNOW }, + { "sk", RTL_TEXTENCODING_ISO_8859_2 }, + { "sl", RTL_TEXTENCODING_ISO_8859_2 }, + { "sq", RTL_TEXTENCODING_ISO_8859_2 }, + { "sv", RTL_TEXTENCODING_ISO_8859_1 }, + { "sw", RTL_TEXTENCODING_ISO_8859_1 }, + { "ta", RTL_TEXTENCODING_DONTKNOW }, + { "th", RTL_TEXTENCODING_DONTKNOW }, + { "tr", RTL_TEXTENCODING_ISO_8859_9 }, + { "tt", RTL_TEXTENCODING_ISO_8859_5 }, + { "uk", RTL_TEXTENCODING_ISO_8859_5 }, + { "ur", RTL_TEXTENCODING_ISO_8859_6 }, + { "uz", RTL_TEXTENCODING_ISO_8859_9 }, + { "vi", RTL_TEXTENCODING_DONTKNOW }, + { "zh", RTL_TEXTENCODING_BIG5 } +}; + +/***************************************************************************** + return the text encoding corresponding to the given locale + *****************************************************************************/ + +rtl_TextEncoding osl_getTextEncodingFromLocale( rtl_Locale * pLocale ) +{ + const _pair *language = 0; + char locale_buf[64] = ""; + char *cp; + + /* default to process locale if pLocale == NULL */ + if( NULL == pLocale ) + osl_getProcessLocale( &pLocale ); + + /* convert rtl_Locale to locale string */ + if( _compose_locale( pLocale, locale_buf, 64 ) ) + { + /* check special handling list (EUC) first */ + const unsigned int members = sizeof( _full_locale_list ) / sizeof( _pair ); + language = _pair_search( locale_buf, _full_locale_list, members); + + if( NULL == language ) + { + /* + * check if there is a charset qualifier at the end of the given locale string + * e.g. de.ISO8859-15 or de.ISO8859-15@euro which strongly indicates what + * charset to use + */ + cp = strrchr( locale_buf, '.' ); + + if( NULL != cp ) + { + const unsigned int members = sizeof( _locale_extension_list ) / sizeof( _pair ); + language = _pair_search( cp + 1, _locale_extension_list, members); + } + } + + /* use iso language code to determine the charset */ + if( NULL == language ) + { + const unsigned int members = sizeof( _iso_language_list ) / sizeof( _pair ); + + /* iso lang codes have 2 charaters */ + locale_buf[2] = '\0'; + + language = _pair_search( locale_buf, _iso_language_list, members); + } + } + + /* a matching item in our list provides a mapping from codeset to + * rtl-codeset */ + if ( language != NULL ) + return language->value; + + return RTL_TEXTENCODING_DONTKNOW; +} + +#ifdef MACOSX +#include "system.h" + +/* OS X locale discovery function */ +int (*pGetOSXLocale)( char *, sal_uInt32 ); + +oslModule SAL_CALL osl_psz_loadModule(const sal_Char *pszModuleName, sal_Int32 nRtldMode); +/***************************************************************************** + return the current process locale + *****************************************************************************/ + +int macosx_getLocale(char *locale, sal_uInt32 bufferLen); + +void _imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + static char *locale = NULL; + + /* basic thread safeness */ +// pthread_mutex_lock( &aLocalMutex ); + + /* Only fetch the locale once and cache it */ + if ( NULL == locale ) + { + + locale = (char *)malloc( 20 ); + if ( locale ) + macosx_getLocale( locale, 20 ); + else + fprintf( stderr, "nlsupport.c: locale allocation returned NULL!\n" ); + } + + /* handle the case where OS specific method of finding locale fails */ + if ( NULL == locale ) + { + /* simulate behavior of setlocale */ + locale = getenv( "LC_ALL" ); + + if( NULL == locale ) + locale = getenv( "LC_CTYPE" ); + + if( NULL == locale ) + locale = getenv( "LANG" ); + + if( NULL == locale ) + locale = "C"; + } + + /* return the locale */ + *ppLocale = _parse_locale( locale ); + + setenv( "LC_ALL", locale, 1); + setenv("LC_CTYPE", locale, 1 ); + setenv("LANG", locale, 1 ); + +#ifdef DEBUG + fprintf( stderr, "nlsupport.c: _imp_getProcessLocale() returning %s as current locale.\n", locale ); +#endif + +// pthread_mutex_unlock( &aLocalMutex ); + +} +#else +/***************************************************************************** + return the current process locale + *****************************************************************************/ + +void _imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + /* simulate behavior off setlocale */ + char * locale = getenv( "LC_ALL" ); + + if( NULL == locale ) + locale = getenv( "LC_CTYPE" ); + + if( NULL == locale ) + locale = getenv( "LANG" ); + + if( NULL == locale ) + locale = "C"; + + *ppLocale = _parse_locale( locale ); +} +#endif + +/***************************************************************************** + set the current process locale + *****************************************************************************/ + +int _imp_setProcessLocale( rtl_Locale * pLocale ) +{ + char locale_buf[64]; + + /* convert rtl_Locale to locale string */ + if( NULL != _compose_locale( pLocale, locale_buf, 64 ) ) + { + /* only change env vars that exist already */ + if( getenv( "LC_ALL" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) + setenv( "LC_ALL", locale_buf, 1); +#else + setenv( "LC_ALL", locale_buf ); +#endif + } + + if( getenv( "LC_CTYPE" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) + setenv("LC_CTYPE", locale_buf, 1 ); +#else + setenv( "LC_CTYPE", locale_buf ); +#endif + } + + if( getenv( "LANG" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) + setenv("LC_CTYPE", locale_buf, 1 ); +#else + setenv( "LANG", locale_buf ); +#endif + } + } + + return 0; +} + +#endif /* ifdef LINUX || SOLARIS || MACOSX || NETBSD */ + + diff --git a/sal/osl/unx/osxlocale.cxx b/sal/osl/unx/osxlocale.cxx new file mode 100644 index 000000000000..9a20fd9ceb12 --- /dev/null +++ b/sal/osl/unx/osxlocale.cxx @@ -0,0 +1,129 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include <sal/types.h> +#include <assert.h> + +#include <premac.h> +#include <CoreServices/CoreServices.h> +#include <CoreFoundation/CoreFoundation.h> +#include <postmac.h> + +namespace /* private */ +{ + template <typename T> + class CFGuard + { + public: + explicit CFGuard(T& rT) : rT_(rT) {} + ~CFGuard() { if (rT_) CFRelease(rT_); } + private: + T& rT_; + }; + + typedef CFGuard<CFArrayRef> CFArrayGuard; + typedef CFGuard<CFStringRef> CFStringGuard; + typedef CFGuard<CFPropertyListRef> CFPropertyListGuard; + + /** Get the current process locale from system + */ + CFStringRef getProcessLocale() + { + CFPropertyListRef pref = CFPreferencesCopyAppValue(CFSTR("AppleLocale"), kCFPreferencesCurrentApplication); + CFPropertyListGuard proplGuard(pref); + + if (pref == NULL) // return fallback value 'en_US' + return CFStringCreateWithCString(kCFAllocatorDefault, "en_US", kCFStringEncodingASCII); + + CFStringRef sref = (CFGetTypeID(pref) == CFArrayGetTypeID()) ? (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)pref, 0) : (CFStringRef)pref; + + // NOTE: this API is only available with Mac OS X >=10.3. We need to use it because + // Apple used non-ISO values on systems <10.2 like "German" for instance but didn't + // upgrade those values during upgrade to newer Mac OS X versions. See also #i54337# + return CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, sref); + } +} // namespace private + +/** Grab current locale from system. +*/ +extern "C" { +int macosx_getLocale(char *locale, sal_uInt32 bufferLen) +{ + CFStringRef sref = getProcessLocale(); + CFStringGuard sGuard(sref); + + assert(sref != NULL && "osxlocale.cxx: getProcessLocale must return a non-NULL value"); + + // split the string into substrings; the first two (if there are two) substrings + // are language and country + CFArrayRef subs = CFStringCreateArrayBySeparatingStrings(NULL, sref, CFSTR("_")); + CFArrayGuard arrGuard(subs); + + CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(subs, 0); + CFStringGetCString(lang, locale, bufferLen, kCFStringEncodingASCII); + + // country also available? Assumption: if the array contains more than one + // value the second value is always the country! + if (CFArrayGetCount(subs) > 1) + { + strlcat(locale, "_", bufferLen - strlen(locale)); + + CFStringRef country = (CFStringRef)CFArrayGetValueAtIndex(subs, 1); + CFStringGetCString(country, locale + strlen(locale), bufferLen - strlen(locale), kCFStringEncodingASCII); + } + // Append 'UTF-8' to the locale because the Mac OS X file + // system interface is UTF-8 based and sal tries to determine + // the file system locale from the locale information + strlcat(locale, ".UTF-8", bufferLen - strlen(locale)); + + return noErr; +} +} + + + +/* + * macxp_OSXConvertCFEncodingToIANACharSetName + * + * Convert a CoreFoundation text encoding to an IANA charset name. + */ +extern "C" int macxp_OSXConvertCFEncodingToIANACharSetName( char *buffer, unsigned int bufferLen, CFStringEncoding cfEncoding ) +{ + CFStringRef sCFEncodingName; + + sCFEncodingName = CFStringConvertEncodingToIANACharSetName( cfEncoding ); + CFStringGetCString( sCFEncodingName, buffer, bufferLen, cfEncoding ); + + if ( sCFEncodingName ) + CFRelease( sCFEncodingName ); + + return( noErr ); +} + diff --git a/sal/osl/unx/pipe.c b/sal/osl/unx/pipe.c new file mode 100644 index 000000000000..ede4cd7e074f --- /dev/null +++ b/sal/osl/unx/pipe.c @@ -0,0 +1,592 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/pipe.h> +#include <osl/diagnose.h> +/*#include <osl/signal.h>*/ +#include <osl/thread.h> +#include <osl/interlck.h> + +#include "sockimpl.h" + +#define PIPEDEFAULTPATH "/tmp" +#define PIPEALTERNATEPATH "/var/tmp" + +#define PIPENAMEMASK "OSL_PIPE_%s" +#define SECPIPENAMEMASK "OSL_PIPE_%s_%s" + +sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax); +oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, oslSecurity Security); + +/*#define DEBUG_OSL_PIPE*/ +/*#define TRACE_OSL_PIPE*/ + + +/*****************************************************************************/ +/* enum oslPipeError */ +/*****************************************************************************/ + +static struct +{ + int errcode; + oslPipeError error; +} PipeError[]= { + { 0, osl_Pipe_E_None }, /* no error */ + { EPROTOTYPE, osl_Pipe_E_NoProtocol }, /* Protocol wrong type for socket */ + { ENOPROTOOPT, osl_Pipe_E_NoProtocol }, /* Protocol not available */ + { EPROTONOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol not supported */ + { ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Socket type not supported */ + { EPFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol family not supported */ + { EAFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Address family not supported by */ + /* protocol family */ + { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */ + /* of reset */ + { ECONNABORTED, osl_Pipe_E_ConnectionAbort }, /* Software caused connection abort */ + { ECONNRESET, osl_Pipe_E_ConnectionReset }, /* Connection reset by peer */ + { ENOBUFS, osl_Pipe_E_NoBufferSpace }, /* No buffer space available */ + { ETIMEDOUT, osl_Pipe_E_TimedOut }, /* Connection timed out */ + { ECONNREFUSED, osl_Pipe_E_ConnectionRefused }, /* Connection refused */ + { -1, osl_Pipe_E_invalidError } +}; + + +/* map */ +/* mfe: NOT USED + static int osl_NativeFromPipeError(oslPipeError errorCode) + { + int i = 0; + + while ((PipeError[i].error != osl_Pipe_E_invalidError) && + (PipeError[i].error != errorCode)) i++; + + return PipeError[i].errcode; + + } +*/ + +/* reverse map */ +static oslPipeError osl_PipeErrorFromNative(int nativeType) +{ + int i = 0; + + while ((PipeError[i].error != osl_Pipe_E_invalidError) && + (PipeError[i].errcode != nativeType)) i++; + + return PipeError[i].error; +} + + +/* macros */ +#define ERROR_TO_NATIVE(x) osl_NativeFromPipeError(x) +#define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y) + + +/*****************************************************************************/ +/* osl_create/destroy-PipeImpl */ +/*****************************************************************************/ + +oslPipe __osl_createPipeImpl() +{ + oslPipe pPipeImpl; + + pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl)); + pPipeImpl->m_nRefCount =1; + pPipeImpl->m_bClosed = sal_False; +#if defined(LINUX) + pPipeImpl->m_bIsInShutdown = sal_False; + pPipeImpl->m_bIsAccepting = sal_False; +#endif + return pPipeImpl; +} + +void __osl_destroyPipeImpl(oslPipe pImpl) +{ + if (pImpl != NULL) + free(pImpl); +} + + +/*****************************************************************************/ +/* osl_createPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security) +{ + oslPipe pPipe=0; + rtl_String* strPipeName=0; + sal_Char* pszPipeName=0; + + if ( ustrPipeName != 0 ) + { + rtl_uString2String( &strPipeName, + rtl_uString_getStr(ustrPipeName), + rtl_uString_getLength(ustrPipeName), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszPipeName = rtl_string_getStr(strPipeName); + pPipe = osl_psz_createPipe(pszPipeName, Options, Security); + + if ( strPipeName != 0 ) + { + rtl_string_release(strPipeName); + } + } + + return pPipe; + +} + +oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, + oslSecurity Security) +{ + int Flags; + size_t len; + struct sockaddr_un addr; + + sal_Char name[PATH_MAX + 1]; + oslPipe pPipe; + + if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0) + { + strncpy(name, PIPEDEFAULTPATH, sizeof(name)); + } + else + { + strncpy(name, PIPEALTERNATEPATH, sizeof(name)); + } + + + strncat(name, "/", sizeof(name)); + + if (Security) + { + sal_Char Ident[256]; + + Ident[0] = '\0'; + + OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident))); + + snprintf(&name[strlen(name)], sizeof(name), SECPIPENAMEMASK, Ident, pszPipeName); + } + else + { + snprintf(&name[strlen(name)], sizeof(name), PIPENAMEMASK, pszPipeName); + } + + + /* alloc memory */ + pPipe= __osl_createPipeImpl(); + + /* create socket */ + pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0); + if ( pPipe->m_Socket < 0 ) + { + OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s\n",errno, strerror(errno)); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + +/* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/ + + /* set close-on-exec flag */ + if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1) + { + OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s\n",errno,strerror(errno)); + } + } + + memset(&addr, 0, sizeof(addr)); + + OSL_TRACE("osl_createPipe : Pipe Name '%s'",name); + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, name, sizeof(addr.sun_path)); +#if defined(FREEBSD) + len = SUN_LEN(&addr); +#else + len = sizeof(addr); +#endif + + if ( Options & osl_Pipe_CREATE ) + { + struct stat status; + + /* check if there exists an orphan filesystem entry */ + if ( ( stat(name, &status) == 0) && + ( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) ) + { + if ( connect(pPipe->m_Socket,(struct sockaddr *)&addr,len) >= 0 ) + { + OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s\n",errno,strerror(errno)); + close (pPipe->m_Socket); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + + unlink(name); + } + + /* ok, fs clean */ + if ( bind(pPipe->m_Socket, (struct sockaddr *)&addr, len) < 0 ) + { + OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s\n",errno,strerror(errno)); + close (pPipe->m_Socket); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + + /* Only give access to all if no security handle was specified, otherwise security + depends on umask */ + + if ( !Security ) + chmod(name,S_IRWXU | S_IRWXG |S_IRWXO); + + + strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name)); + + if ( listen(pPipe->m_Socket, 5) < 0 ) + { + OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s\n",errno,strerror(errno)); + unlink(name); /* remove filesystem entry */ + close (pPipe->m_Socket); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + + return (pPipe); + } + else + { /* osl_pipe_OPEN */ + if ( access(name, F_OK) != -1 ) + { + if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 ) + { + return (pPipe); + } + + OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s\n",errno,strerror(errno)); + } + + close (pPipe->m_Socket); + __osl_destroyPipeImpl(pPipe); + return NULL; + } +} + +void SAL_CALL osl_acquirePipe( oslPipe pPipe ) +{ + osl_incrementInterlockedCount( &(pPipe->m_nRefCount) ); +} + +void SAL_CALL osl_releasePipe( oslPipe pPipe ) +{ + + if( 0 == pPipe ) + return; + + if( 0 == osl_decrementInterlockedCount( &(pPipe->m_nRefCount) ) ) + { + if( ! pPipe->m_bClosed ) + osl_closePipe( pPipe ); + + __osl_destroyPipeImpl( pPipe ); + } +} + +void SAL_CALL osl_closePipe( oslPipe pPipe ) +{ + int nRet; +#if defined(LINUX) + size_t len; + struct sockaddr_un addr; + int fd; +#endif + int ConnFD; + + if( ! pPipe ) + { + return; + } + + if( pPipe->m_bClosed ) + { + return; + } + + ConnFD = pPipe->m_Socket; + + /* + Thread does not return from accept on linux, so + connect to the accepting pipe + */ +#if defined(LINUX) + if ( pPipe->m_bIsAccepting ) + { + pPipe->m_bIsInShutdown = sal_True; + pPipe->m_Socket = -1; + fd = socket(AF_UNIX, SOCK_STREAM, 0); + memset(&addr, 0, sizeof(addr)); + + OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe->m_Name); + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, pPipe->m_Name, sizeof(addr.sun_path)); + len = sizeof(addr); + + nRet = connect( fd, (struct sockaddr *)&addr, len); +#if OSL_DEBUG_LEVEL > 1 + if ( nRet < 0 ) + { + perror("connect in osl_destroyPipe"); + } +#endif /* OSL_DEBUG_LEVEL */ + close(fd); + } +#endif /* LINUX */ + + + nRet = shutdown(ConnFD, 2); + if ( nRet < 0 ) + { + OSL_TRACE("shutdown in destroyPipe failed : '%s'\n",strerror(errno)); + } + + nRet = close(ConnFD); + if ( nRet < 0 ) + { + OSL_TRACE("close in destroyPipe failed : '%s'\n",strerror(errno)); + } + /* remove filesystem entry */ + if ( strlen(pPipe->m_Name) > 0 ) + { + unlink(pPipe->m_Name); + } + pPipe->m_bClosed = sal_True; + +/* OSL_TRACE("Out osl_destroyPipe"); */ +} + + +/*****************************************************************************/ +/* osl_acceptPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe) +{ + int s, flags; + oslPipe pAcceptedPipe; + + OSL_ASSERT(pPipe); + if ( pPipe == 0 ) + { + return NULL; + } + + OSL_ASSERT(strlen(pPipe->m_Name) > 0); + +#if defined(LINUX) + pPipe->m_bIsAccepting = sal_True; +#endif + + s = accept(pPipe->m_Socket, NULL, NULL); + +#if defined(LINUX) + pPipe->m_bIsAccepting = sal_False; +#endif + + if (s < 0) + { + OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno)); + return NULL; + } + +#if defined(LINUX) + if ( pPipe->m_bIsInShutdown ) + { + close(s); + return NULL; + } +#endif /* LINUX */ + else + { + /* alloc memory */ + pAcceptedPipe= __osl_createPipeImpl(); + + OSL_ASSERT(pAcceptedPipe); + if(pAcceptedPipe==NULL) + { + close(s); + return NULL; + } + + /* set close-on-exec flag */ + if (!((flags = fcntl(s, F_GETFD, 0)) < 0)) + { + flags |= FD_CLOEXEC; + if (fcntl(s, F_SETFD, flags) < 0) + { + OSL_TRACE("osl_acceptPipe: error changing socket flags. " + "Errno: %d; %s",errno,strerror(errno)); + } + } + + pAcceptedPipe->m_Socket = s; + } + + return pAcceptedPipe; +} + +/*****************************************************************************/ +/* osl_receivePipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe, + void* pBuffer, + sal_Int32 BytesToRead) +{ + int nRet = 0; + + OSL_ASSERT(pPipe); + + if ( pPipe == 0 ) + { + OSL_TRACE("osl_receivePipe : Invalid socket"); + errno=EINVAL; + return -1; + } + + nRet = recv(pPipe->m_Socket, + (sal_Char*)pBuffer, + BytesToRead, 0); + + if ( nRet <= 0 ) + { + OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno)); + } + + return nRet; +} + + +/*****************************************************************************/ +/* osl_sendPipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe, + const void* pBuffer, + sal_Int32 BytesToSend) +{ + int nRet=0; + + OSL_ASSERT(pPipe); + + if ( pPipe == 0 ) + { + OSL_TRACE("osl_sendPipe : Invalid socket"); + errno=EINVAL; + return -1; + } + + nRet = send(pPipe->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, 0); + + + if ( nRet <= 0 ) + { + OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno)); + } + + return nRet; +} + + +/*****************************************************************************/ +/* osl_getLastPipeError */ +/*****************************************************************************/ +oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe) +{ + (void) pPipe; /* unused */ + return ERROR_FROM_NATIVE(errno); +} + + +sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n ) +{ + /* loop until all desired bytes were send or an error occured */ + sal_Int32 BytesSend= 0; + sal_Int32 BytesToSend= n; + + OSL_ASSERT(pPipe); + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToSend -= RetVal; + BytesSend += RetVal; + pBuffer= (sal_Char*)pBuffer + RetVal; + } + + return BytesSend; +} + +sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n ) +{ + /* loop until all desired bytes were read or an error occured */ + sal_Int32 BytesRead= 0; + sal_Int32 BytesToRead= n; + + OSL_ASSERT( pPipe ); + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToRead -= RetVal; + BytesRead += RetVal; + pBuffer= (sal_Char*)pBuffer + RetVal; + } + return BytesRead; +} + + diff --git a/sal/osl/unx/process.c b/sal/osl/unx/process.c new file mode 100644 index 000000000000..300a1446e81a --- /dev/null +++ b/sal/osl/unx/process.c @@ -0,0 +1,1536 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/* + * ToDo: + * - cleanup of process status things + * - cleanup of process spawning + * - cleanup of resource transfer + */ + +#if defined(SOLARIS) + // The procfs may only be used without LFS in 32bits. +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + + +#ifdef FREEBSD +#include <machine/param.h> +#endif + +#include "system.h" +#if defined(SOLARIS) +# include <sys/procfs.h> +#endif +#include <osl/diagnose.h> +#include <osl/mutex.h> + +#ifndef _OSL_CONDITN_H_ +#include <osl/conditn.h> +#endif +#include <osl/thread.h> +#include <osl/file.h> +#include <osl/signal.h> +#include <rtl/alloc.h> + +#include <grp.h> + +#include "procimpl.h" +#include "sockimpl.h" +#include "secimpl.h" + + +#define MAX_ARGS 255 +#define MAX_ENVS 255 + +#if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD) +#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) +#endif + +/* implemented in file.c */ +extern oslFileError FileURLToPath( char *, size_t, rtl_uString* ); +extern oslFileHandle osl_createFileHandleFromFD( int fd ); + +/****************************************************************************** + * + * Data Type Definition + * + ******************************************************************************/ + +typedef struct { + int m_hPipe; + int m_hConn; + sal_Char m_Name[PATH_MAX + 1]; +} Pipe; + +typedef struct { + const sal_Char* m_pszArgs[MAX_ARGS + 1]; + oslProcessOption m_options; + const sal_Char* m_pszDir; + sal_Char* m_pszEnv[MAX_ENVS + 1]; + uid_t m_uid; + gid_t m_gid; + sal_Char* m_name; + oslCondition m_started; + oslProcessImpl* m_pProcImpl; + oslFileHandle *m_pInputWrite; + oslFileHandle *m_pOutputRead; + oslFileHandle *m_pErrorRead; +} ProcessData; + +typedef struct _oslPipeImpl { + int m_Socket; + sal_Char m_Name[PATH_MAX + 1]; +} oslPipeImpl; + + +/****************************************************************************** + * + * Function Declarations + * + *****************************************************************************/ + +oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, + sal_Char *pszArguments[], + oslProcessOption Options, + oslSecurity Security, + sal_Char *pszDirectory, + sal_Char *pszEnvironments[], + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead ); + + +oslProcessError SAL_CALL osl_searchPath_impl( + const sal_Char* pszName, + const sal_Char* pszPath, + sal_Char Separator, + sal_Char *pszBuffer, + sal_uInt32 Max); + + +sal_Bool osl_getFullPath(const sal_Char* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen); + +static oslProcessImpl* ChildList; +static oslMutex ChildListMutex; + +/****************************************************************************** + Deprecated + Old and buggy implementation of osl_searchPath used only by + osl_psz_executeProcess. + A new implemenation is in file_path_helper.cxx + *****************************************************************************/ + +oslProcessError SAL_CALL osl_searchPath_impl(const sal_Char* pszName, const sal_Char* pszPath, + sal_Char Separator, sal_Char *pszBuffer, sal_uInt32 Max) +{ + sal_Char path[PATH_MAX + 1]; + sal_Char *pchr; + + path[0] = '\0'; + + OSL_ASSERT(pszName != NULL); + + if ( pszName == 0 ) + { + return osl_Process_E_NotFound; + } + + if (pszPath == NULL) + pszPath = "PATH"; + + if (Separator == '\0') + Separator = ':'; + + + if ( (pchr = getenv(pszPath)) != 0 ) + { + sal_Char *pstr; + + while (*pchr != '\0') + { + pstr = path; + + while ((*pchr != '\0') && (*pchr != Separator)) + *pstr++ = *pchr++; + + if ((pstr > path) && ((*(pstr - 1) != '/'))) + *pstr++ = '/'; + + *pstr = '\0'; + + strcat(path, pszName); + + if (access(path, 0) == 0) + { + char szRealPathBuf[PATH_MAX] = ""; + + if( NULL == realpath(path, szRealPathBuf) || (strlen(szRealPathBuf) >= (sal_uInt32)Max)) + return osl_Process_E_Unknown; + + strcpy(pszBuffer, path); + + return osl_Process_E_None; + } + + if (*pchr == Separator) + pchr++; + } + } + + return osl_Process_E_NotFound; +} + +/****************************************************************************** + * + * New io resource transfer functions + * + *****************************************************************************/ + + +/********************************************** + sendFdPipe + *********************************************/ + +static sal_Bool sendFdPipe(int PipeFD, int SocketFD) +{ + sal_Bool bRet = sal_False; + + struct iovec iov[1]; + struct msghdr msg; + char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ + int nSend; + int RetCode=0; + +#if defined(IOCHANNEL_TRANSFER_BSD) + + OSL_TRACE("IOCHANNEL_TRANSFER_BSD send"); +/* OSL_TRACE("sending fd %i\n",SocketFD); */ + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + + msg.msg_accrights = (caddr_t) &SocketFD; /* addr of descriptor */ + msg.msg_accrightslen = sizeof(int); /* pass 1 descriptor */ + buf[1] = 0; /* zero status means OK */ + buf[0] = 0; /* null byte flag to recv_fd() */ + +#else + + struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN); + + OSL_TRACE("!!!!!! IOCHANNEL_TRANSFER_BSD_RENO send"); +/* OSL_TRACE("sending fd %i\n",SocketFD); */ + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = (caddr_t) cmptr; + msg.msg_controllen = CONTROLLEN; + + cmptr->cmsg_level = SOL_SOCKET; + cmptr->cmsg_type = SCM_RIGHTS; + cmptr->cmsg_len = CONTROLLEN; + memcpy(CMSG_DATA(cmptr), &SocketFD, sizeof(int)); + +#endif + + if ( ( nSend = sendmsg(PipeFD, &msg, 0) ) > 0 ) + { + bRet = sal_True; + OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend); + + } + else + { + OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); + } + + nSend=read(PipeFD,&RetCode,sizeof(RetCode)); + + if ( nSend > 0 && RetCode == 1 ) + { + OSL_TRACE("sendFdPipe : resource was received\n"); + } + else + { + OSL_TRACE("sendFdPipe : resource wasn't received\n"); + } + +#if defined(IOCHANNEL_TRANSFER_BSD_RENO) + free(cmptr); +#endif + + return bRet; +} + +/********************************************** + receiveFdPipe + *********************************************/ + +static oslSocket receiveFdPipe(int PipeFD) +{ + oslSocket pSocket = 0; + struct msghdr msghdr; + struct iovec iov[1]; + char buffer[2]; + sal_Int32 nRead; + int newfd=-1; + int nRetCode=0; +/* char *ptr; */ + +#if defined(IOCHANNEL_TRANSFER_BSD) + + OSL_TRACE("IOCHANNEL_TRANSFER_BSD receive\n"); + + iov[0].iov_base = buffer; + iov[0].iov_len = sizeof(buffer); + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = iov; + msghdr.msg_iovlen = 1; + msghdr.msg_accrights = (caddr_t) &newfd; /* addr of descriptor */ + msghdr.msg_accrightslen = sizeof(int); /* receive 1 descriptor */ + +#else + struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN); + + OSL_TRACE(" !!!! IOCHANNEL_TRANSFER_BSD_RENO receive"); + + iov[0].iov_base = buffer; + iov[0].iov_len = sizeof(buffer); + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = iov; + msghdr.msg_iovlen = 1; + + msghdr.msg_control = (caddr_t) cmptr; + msghdr.msg_controllen = CONTROLLEN; + +#endif + + +#if defined(IOCHANNEL_TRANSFER_BSD) + + if ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) + { + OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead); + } +#else + + if ( ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) && + ( msghdr.msg_controllen == CONTROLLEN ) ) + { + OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead); + memcpy(&newfd, CMSG_DATA(cmptr), sizeof(int)); + } +#endif + else + { + OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno)); + } + + if ( newfd >= 0 ) + { + pSocket = __osl_createSocketImpl(newfd); + nRetCode=1; + OSL_TRACE("received fd %i\n",newfd); + } + + OSL_TRACE("receiveFdPipe : writing back %i",nRetCode); + nRead=write(PipeFD,&nRetCode,sizeof(nRetCode)); + +#if defined(IOCHANNEL_TRANSFER_BSD_RENO) + free(cmptr); +#endif + + return pSocket; +} + +/********************************************** + osl_sendResourcePipe + *********************************************/ + +sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket) +{ + sal_Bool bRet = sal_False; + + if ( pSocket == 0 || pPipe == 0 ) + { + return sal_False; + } + + bRet = sendFdPipe(pPipe->m_Socket,pSocket->m_Socket); + + return bRet; +} + +/********************************************** + osl_receiveResourcePipe + *********************************************/ + +oslSocket osl_receiveResourcePipe(oslPipe pPipe) +{ + oslSocket pSocket=0; + + if ( pPipe == 0 ) + { + return 0; + } + + pSocket = receiveFdPipe(pPipe->m_Socket); + + return (oslSocket) pSocket; +} + + + +/****************************************************************************** + * + * Functions for starting a process + * + *****************************************************************************/ + +static void ChildStatusProc(void *pData) +{ + pid_t pid = -1; + int status = 0; + int channel[2]; + ProcessData data; + ProcessData *pdata; + int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 }; + + pdata = (ProcessData *)pData; + + /* make a copy of our data, because forking will only copy + our local stack of the thread, so the process data will not be accessible + in our child process */ + memcpy(&data, pData, sizeof(data)); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1) + status = errno; + + fcntl(channel[0], F_SETFD, FD_CLOEXEC); + fcntl(channel[1], F_SETFD, FD_CLOEXEC); + + /* Create redirected IO pipes */ + if ( status == 0 && data.m_pInputWrite ) + if (pipe( stdInput ) == -1) + status = errno; + + if ( status == 0 && data.m_pOutputRead ) + if (pipe( stdOutput ) == -1) + status = errno; + + if ( status == 0 && data.m_pErrorRead ) + if (pipe( stdError ) == -1) + status = errno; + + if ( (status == 0) && ((pid = fork()) == 0) ) + { + /* Child */ + int chstatus = 0; + sal_Int32 nWrote; + + if (channel[0] != -1) close(channel[0]); + + if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid()))) + { + OSL_ASSERT(geteuid() == 0); /* must be root */ + + if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0)) + OSL_TRACE("Failed to change uid and guid, errno=%d (%s)\n", errno, strerror(errno)); +#if defined(LINUX) || defined (FREEBSD) + unsetenv("HOME"); +#else + putenv("HOME="); +#endif + } + + if (data.m_pszDir) + chstatus = chdir(data.m_pszDir); + + if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid())))) + { + int i; + for (i = 0; data.m_pszEnv[i] != NULL; i++) + { + if (strchr(data.m_pszEnv[i], '=') == NULL) + { + unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/ + } + else + { + putenv(data.m_pszEnv[i]); /*TODO: check error return*/ + } + } + + OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]); + + /* Connect std IO to pipe ends */ + + /* Write end of stdInput not used in child process */ + if (stdInput[1] != -1) close( stdInput[1] ); + + /* Read end of stdOutput not used in child process */ + if (stdOutput[0] != -1) close( stdOutput[0] ); + + /* Read end of stdError not used in child process */ + if (stdError[0] != -1) close( stdError[0] ); + + /* Redirect pipe ends to std IO */ + + if ( stdInput[0] != STDIN_FILENO ) + { + dup2( stdInput[0], STDIN_FILENO ); + if (stdInput[0] != -1) close( stdInput[0] ); + } + + if ( stdOutput[1] != STDOUT_FILENO ) + { + dup2( stdOutput[1], STDOUT_FILENO ); + if (stdOutput[1] != -1) close( stdOutput[1] ); + } + + if ( stdError[1] != STDERR_FILENO ) + { + dup2( stdError[1], STDERR_FILENO ); + if (stdError[1] != -1) close( stdError[1] ); + } + + pid=execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs); + + } + + OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno, strerror(errno)); + + OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); + + /* if we reach here, something went wrong */ + nWrote = write(channel[1], &errno, sizeof(errno)); + if (nWrote != sizeof(errno)) + OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); + + if (channel[1] != -1) close(channel[1]); + + _exit(255); + } + else + { /* Parent */ + int i = -1; + if (channel[1] != -1) close(channel[1]); + + /* Close unused pipe ends */ + if (stdInput[0] != -1) close( stdInput[0] ); + if (stdOutput[1] != -1) close( stdOutput[1] ); + if (stdError[1] != -1) close( stdError[1] ); + + if (pid > 0) + { + while (((i = read(channel[0], &status, sizeof(status))) < 0)) + { + if (errno != EINTR) + break; + } + } + + if (channel[0] != -1) close(channel[0]); + + if ((pid > 0) && (i == 0)) + { + pid_t child_pid; + osl_acquireMutex(ChildListMutex); + + pdata->m_pProcImpl->m_pid = pid; + pdata->m_pProcImpl->m_pnext = ChildList; + ChildList = pdata->m_pProcImpl; + + /* Store used pipe ends in data structure */ + + if ( pdata->m_pInputWrite ) + *(pdata->m_pInputWrite) = osl_createFileHandleFromFD( stdInput[1] ); + + if ( pdata->m_pOutputRead ) + *(pdata->m_pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] ); + + if ( pdata->m_pErrorRead ) + *(pdata->m_pErrorRead) = osl_createFileHandleFromFD( stdError[0] ); + + osl_releaseMutex(ChildListMutex); + + osl_setCondition(pdata->m_started); + + do + { + child_pid = waitpid(pid, &status, 0); + } while ( 0 > child_pid && EINTR == errno ); + + if ( child_pid < 0) + { + OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno, strerror(errno)); + + /* + We got an other error than EINTR. Anyway we have to wake up the + waiting thread under any circumstances */ + + child_pid = pid; + } + + + if ( child_pid > 0 ) + { + oslProcessImpl* pChild; + + osl_acquireMutex(ChildListMutex); + + pChild = ChildList; + + /* check if it is one of our child processes */ + while (pChild != NULL) + { + if (pChild->m_pid == child_pid) + { + if (WIFEXITED(status)) + pChild->m_status = WEXITSTATUS(status); + else + pChild->m_status = -1; + + osl_setCondition(pChild->m_terminated); + } + + pChild = pChild->m_pnext; + } + + osl_releaseMutex(ChildListMutex); + } + } + else + { + OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); + OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)\n", status, strerror(status)); + + /* Close pipe ends */ + if ( pdata->m_pInputWrite ) + *pdata->m_pInputWrite = NULL; + + if ( pdata->m_pOutputRead ) + *pdata->m_pOutputRead = NULL; + + if ( pdata->m_pErrorRead ) + *pdata->m_pErrorRead = NULL; + + if (stdInput[1] != -1) close( stdInput[1] ); + if (stdOutput[0] != -1) close( stdOutput[0] ); + if (stdError[0] != -1) close( stdError[0] ); + + //if pid > 0 then a process was created, even if it later failed + //e.g. bash searching for a command to execute, and we still + //need to clean it up to avoid "defunct" processes + if (pid > 0) + { + pid_t child_pid; + do + { + child_pid = waitpid(pid, &status, 0); + } while ( 0 > child_pid && EINTR == errno ); + } + + /* notify (and unblock) parent thread */ + osl_setCondition(pdata->m_started); + } + } +} + +/********************************************** + osl_executeProcess_WithRedirectedIO + *********************************************/ + +oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO( + rtl_uString *ustrImageName, + rtl_uString *ustrArguments[], + sal_uInt32 nArguments, + oslProcessOption Options, + oslSecurity Security, + rtl_uString *ustrWorkDir, + rtl_uString *ustrEnvironment[], + sal_uInt32 nEnvironmentVars, + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead + ) +{ + + oslProcessError Error; + sal_Char* pszWorkDir=0; + sal_Char** pArguments=0; + sal_Char** pEnvironment=0; + unsigned int idx; + + char szImagePath[PATH_MAX] = ""; + char szWorkDir[PATH_MAX] = ""; + + if ( ustrImageName && ustrImageName->length ) + { + FileURLToPath( szImagePath, PATH_MAX, ustrImageName ); + } + + if ( ustrWorkDir != 0 && ustrWorkDir->length ) + { + FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir ); + pszWorkDir = szWorkDir; + } + + if ( pArguments == 0 && nArguments > 0 ) + { + pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) ); + } + + + for ( idx = 0 ; idx < nArguments ; ++idx ) + { + rtl_String* strArg =0; + + + rtl_uString2String( &strArg, + rtl_uString_getStr(ustrArguments[idx]), + rtl_uString_getLength(ustrArguments[idx]), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + + pArguments[idx]=strdup(rtl_string_getStr(strArg)); + rtl_string_release(strArg); + pArguments[idx+1]=0; + } + + for ( idx = 0 ; idx < nEnvironmentVars ; ++idx ) + { + rtl_String* strEnv=0; + + if ( pEnvironment == 0 ) + { + pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) ); + } + + rtl_uString2String( &strEnv, + rtl_uString_getStr(ustrEnvironment[idx]), + rtl_uString_getLength(ustrEnvironment[idx]), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + + pEnvironment[idx]=strdup(rtl_string_getStr(strEnv)); + rtl_string_release(strEnv); + pEnvironment[idx+1]=0; + } + + + Error = osl_psz_executeProcess(szImagePath, + pArguments, + Options, + Security, + pszWorkDir, + pEnvironment, + pProcess, + pInputWrite, + pOutputRead, + pErrorRead + ); + + if ( pArguments != 0 ) + { + for ( idx = 0 ; idx < nArguments ; ++idx ) + { + if ( pArguments[idx] != 0 ) + { + free(pArguments[idx]); + } + } + free(pArguments); + } + + if ( pEnvironment != 0 ) + { + for ( idx = 0 ; idx < nEnvironmentVars ; ++idx ) + { + if ( pEnvironment[idx] != 0 ) + { + free(pEnvironment[idx]); + } + } + free(pEnvironment); + } + + return Error; +} + +/********************************************** + osl_executeProcess + *********************************************/ + +oslProcessError SAL_CALL osl_executeProcess( + rtl_uString *ustrImageName, + rtl_uString *ustrArguments[], + sal_uInt32 nArguments, + oslProcessOption Options, + oslSecurity Security, + rtl_uString *ustrWorkDir, + rtl_uString *ustrEnvironment[], + sal_uInt32 nEnvironmentVars, + oslProcess *pProcess + ) +{ + return osl_executeProcess_WithRedirectedIO( + ustrImageName, + ustrArguments, + nArguments, + Options, + Security, + ustrWorkDir, + ustrEnvironment, + nEnvironmentVars, + pProcess, + NULL, + NULL, + NULL + ); +} + +/********************************************** + osl_psz_executeProcess + *********************************************/ + +oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, + sal_Char *pszArguments[], + oslProcessOption Options, + oslSecurity Security, + sal_Char *pszDirectory, + sal_Char *pszEnvironments[], + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead + ) +{ + int i; + sal_Char path[PATH_MAX + 1]; + ProcessData Data; + oslThread hThread; + + path[0] = '\0'; + + memset(&Data,0,sizeof(ProcessData)); + Data.m_pInputWrite = pInputWrite; + Data.m_pOutputRead = pOutputRead; + Data.m_pErrorRead = pErrorRead; + + if (pszImageName == NULL) + pszImageName = pszArguments[0]; + + OSL_ASSERT(pszImageName != NULL); + + if ( pszImageName == 0 ) + { + return osl_Process_E_NotFound; + } + + if ((Options & osl_Process_SEARCHPATH) && + (osl_searchPath_impl(pszImageName, NULL, '\0', path, sizeof(path)) == osl_Process_E_None)) + pszImageName = path; + + Data.m_pszArgs[0] = strdup(pszImageName); + Data.m_pszArgs[1] = 0; + + if ( pszArguments != 0 ) + { + for (i = 0; ((i + 2) < MAX_ARGS) && (pszArguments[i] != NULL); i++) + Data.m_pszArgs[i+1] = strdup(pszArguments[i]); + Data.m_pszArgs[i+2] = NULL; + } + + Data.m_options = Options; + Data.m_pszDir = (pszDirectory != NULL) ? strdup(pszDirectory) : NULL; + + if (pszEnvironments != NULL) + { + for (i = 0; ((i + 1) < MAX_ENVS) && (pszEnvironments[i] != NULL); i++) + Data.m_pszEnv[i] = strdup(pszEnvironments[i]); + Data.m_pszEnv[i+1] = NULL; + } + else + Data.m_pszEnv[0] = NULL; + + if (Security != NULL) + { + Data.m_uid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_uid; + Data.m_gid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_gid; + Data.m_name = ((oslSecurityImpl*)Security)->m_pPasswd.pw_name; + } + else + Data.m_uid = (uid_t)-1; + + Data.m_pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); + Data.m_pProcImpl->m_pid = 0; + Data.m_pProcImpl->m_terminated = osl_createCondition(); + Data.m_pProcImpl->m_pnext = NULL; + + if (ChildListMutex == NULL) + ChildListMutex = osl_createMutex(); + + Data.m_started = osl_createCondition(); + + hThread = osl_createThread(ChildStatusProc, &Data); + + osl_waitCondition(Data.m_started, NULL); + osl_destroyCondition(Data.m_started); + + for (i = 0; Data.m_pszArgs[i] != NULL; i++) + free((void *)Data.m_pszArgs[i]); + + for (i = 0; Data.m_pszEnv[i] != NULL; i++) + free((void *)Data.m_pszEnv[i]); + + if ( Data.m_pszDir != 0 ) + { + free((void *)Data.m_pszDir); + } + + osl_destroyThread(hThread); + + if (Data.m_pProcImpl->m_pid != 0) + { + *pProcess = Data.m_pProcImpl; + + if (Options & osl_Process_WAIT) + osl_joinProcess(*pProcess); + + return osl_Process_E_None; + } + + osl_destroyCondition(Data.m_pProcImpl->m_terminated); + free(Data.m_pProcImpl); + + return osl_Process_E_Unknown; +} + + +/****************************************************************************** + * + * Functions for processes + * + *****************************************************************************/ + + +/********************************************** + osl_terminateProcess + *********************************************/ + +oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process) +{ + if (Process == NULL) + return osl_Process_E_Unknown; + + if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0) + { + switch (errno) + { + case EPERM: + return osl_Process_E_NoPermission; + + case ESRCH: + return osl_Process_E_NotFound; + + default: + return osl_Process_E_Unknown; + } + } + + return osl_Process_E_None; +} + +/********************************************** + osl_getProcess + *********************************************/ + +oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident) +{ + oslProcessImpl *pProcImpl; + + if (kill(Ident, 0) != -1) + { + oslProcessImpl* pChild; + + if (ChildListMutex == NULL) + ChildListMutex = osl_createMutex(); + + osl_acquireMutex(ChildListMutex); + + pChild = ChildList; + + /* check if it is one of our child processes */ + while (pChild != NULL) + { + if (Ident == (sal_uInt32) pChild->m_pid) + break; + + pChild = pChild->m_pnext; + } + + pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); + pProcImpl->m_pid = Ident; + pProcImpl->m_terminated = osl_createCondition(); + + if (pChild != NULL) + { + /* process is a child so insert into list */ + pProcImpl->m_pnext = pChild->m_pnext; + pChild->m_pnext = pProcImpl; + + pProcImpl->m_status = pChild->m_status; + + if (osl_checkCondition(pChild->m_terminated)) + osl_setCondition(pProcImpl->m_terminated); + } + else + pProcImpl->m_pnext = NULL; + + osl_releaseMutex(ChildListMutex); + } + else + pProcImpl = NULL; + + return (pProcImpl); +} + +/********************************************** + osl_freeProcessHandle + *********************************************/ + +void SAL_CALL osl_freeProcessHandle(oslProcess Process) +{ + if (Process != NULL) + { + oslProcessImpl *pChild, *pPrev = NULL; + + OSL_ASSERT(ChildListMutex != NULL); + + if ( ChildListMutex == 0 ) + { + return; + } + + osl_acquireMutex(ChildListMutex); + + pChild = ChildList; + + /* remove process from child list */ + while (pChild != NULL) + { + if (pChild == (oslProcessImpl*)Process) + { + if (pPrev != NULL) + pPrev->m_pnext = pChild->m_pnext; + else + ChildList = pChild->m_pnext; + + break; + } + + pPrev = pChild; + pChild = pChild->m_pnext; + } + + osl_releaseMutex(ChildListMutex); + + osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated); + + free(Process); + } +} + +#if defined(LINUX) +struct osl_procStat +{ + /* from 'stat' */ + pid_t pid; /* pid */ + char command[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */ + char state; /* state (running, stopped, ...) */ + pid_t ppid; /* parent pid */ + pid_t pgrp; /* parent group */ + int session; /* session ID */ + int tty; /* no of tty */ + pid_t tpgid; /* group of process owning the tty */ + unsigned long flags; /* flags dunno */ + unsigned long minflt; /* minor page faults */ + unsigned long cminflt; /* minor page faults with children */ + unsigned long majflt; /* major page faults */ + unsigned long cmajflt; /* major page faults with children */ + unsigned long utime; /* no of jiffies in user mode */ + unsigned long stime; /* no of jiffies in kernel mode */ + unsigned long cutime; /* no of jiffies in user mode with children */ + unsigned long cstime; /* no of jiffies in kernel mode with children */ + unsigned long priority; /* nice value + 15 (kernel scheduling prio)*/ + long nice; /* nice value */ + long timeout; /* no of jiffies of next process timeout */ + long itrealvalue; /* no jiffies before next SIGALRM */ + unsigned long starttime; /* process started this no of jiffies after boot */ + unsigned long vsize; /* virtual memory size (in bytes) */ + long rss; /* resident set size (in pages) */ + unsigned long rss_rlim; /* rss limit (in bytes) */ + unsigned long startcode; /* address above program text can run */ + unsigned long endcode; /* address below program text can run */ + unsigned long startstack; /* address of start of stack */ + unsigned long kstkesp; /* current value of 'esp' (stack pointer) */ + unsigned long kstkeip; /* current value of 'eip' (instruction pointer) */ + /* mfe: Linux > 2.1.7x have more signals (88) */ +/*#ifdef LINUX */ + char signal[24]; /* pending signals */ + char blocked[24]; /* blocked signals */ + char sigignore[24]; /* ignored signals */ + char sigcatch[24]; /* catched signals */ +/*#else*/ +/* long long signal;*/ +/* long long blocked;*/ +/* long long sigignore;*/ +/* long long sigcatch;*/ +/*#endif */ + unsigned long wchan; /* 'channel' the process is waiting in */ + unsigned long nswap; /* ? */ + unsigned long cnswap; /* ? */ + + /* from 'status' */ + int ruid; /* real uid */ + int euid; /* effective uid */ + int suid; /* saved uid */ + int fuid; /* file access uid */ + int rgid; /* real gid */ + int egid; /* effective gid */ + int sgid; /* saved gid */ + int fgid; /* file access gid */ + unsigned long vm_size; /* like vsize but on kb */ + unsigned long vm_lock; /* locked pages in kb */ + unsigned long vm_rss; /* like rss but in kb */ + unsigned long vm_data; /* data size */ + unsigned long vm_stack; /* stack size */ + unsigned long vm_exe; /* executable size */ + unsigned long vm_lib; /* library size */ +}; + +/********************************************** + osl_getProcStat + *********************************************/ + +sal_Bool osl_getProcStat(pid_t pid, struct osl_procStat* procstat) +{ + int fd = 0; + sal_Bool bRet = sal_False; + char name[PATH_MAX + 1]; + snprintf(name, sizeof(name), "/proc/%u/stat", pid); + + if ((fd = open(name,O_RDONLY)) >=0 ) + { + char* tmp=0; + char prstatbuf[512]; + memset(prstatbuf,0,512); + bRet = read(fd,prstatbuf,511) == 511; + + close(fd); + /*printf("%s\n\n",prstatbuf);*/ + + if (!bRet) + return sal_False; + + tmp = strrchr(prstatbuf, ')'); + *tmp = '\0'; + memset(procstat->command, 0, sizeof(procstat->command)); + + sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command); + sscanf(tmp + 2, + "%c" + "%i %i %i %i %i" + "%lu %lu %lu %lu %lu" + "%lu %lu %lu %lu" + "%lu %li %li %li" + "%lu %lu %li %lu" + "%lu %lu %lu %lu %lu" + "%s %s %s %s" + "%lu %lu %lu", + &procstat->state, + &procstat->ppid, &procstat->pgrp, &procstat->session, &procstat->tty, &procstat->tpgid, + &procstat->flags, &procstat->minflt, &procstat->cminflt, &procstat->majflt, &procstat->cmajflt, + &procstat->utime, &procstat->stime, &procstat->cutime, &procstat->cstime, + &procstat->priority, &procstat->nice, &procstat->timeout, &procstat->itrealvalue, + &procstat->starttime, &procstat->vsize, &procstat->rss, &procstat->rss_rlim, + &procstat->startcode, &procstat->endcode, &procstat->startstack, &procstat->kstkesp, &procstat->kstkeip, + procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch, + &procstat->wchan, &procstat->nswap, &procstat->cnswap + ); + } + return bRet; +} + +/********************************************** + osl_getProcStatus + *********************************************/ + +sal_Bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat) +{ + int fd = 0; + char name[PATH_MAX + 1]; + snprintf(name, sizeof(name), "/proc/%u/status", pid); + + sal_Bool bRet = sal_False; + + if ((fd = open(name,O_RDONLY)) >=0 ) + { + char* tmp=0; + char prstatusbuf[512]; + memset(prstatusbuf,0,512); + bRet = read(fd,prstatusbuf,511) == 511; + + close(fd); + + /* printf("\n\n%s\n\n",prstatusbuf);*/ + + if (!bRet) + return sal_False; + + tmp = strstr(prstatusbuf,"Uid:"); + if(tmp) + { + sscanf(tmp,"Uid:\t%d\t%d\t%d\t%d", + &procstat->ruid, &procstat->euid, &procstat->suid, &procstat->fuid + ); + } + + + tmp = strstr(prstatusbuf,"Gid:"); + if(tmp) + { + sscanf(tmp,"Gid:\t%d\t%d\t%d\t%d", + &procstat->rgid, &procstat->egid, &procstat->sgid, &procstat->fgid + ); + } + + tmp = strstr(prstatusbuf,"VmSize:"); + if(tmp) + { + sscanf(tmp, + "VmSize: %lu kB\n" + "VmLck: %lu kB\n" + "VmRSS: %lu kB\n" + "VmData: %lu kB\n" + "VmStk: %lu kB\n" + "VmExe: %lu kB\n" + "VmLib: %lu kB\n", + &procstat->vm_size, &procstat->vm_lock, &procstat->vm_rss, &procstat->vm_data, + &procstat->vm_stack, &procstat->vm_exe, &procstat->vm_lib + ); + } + + tmp = strstr(prstatusbuf,"SigPnd:"); + if(tmp) + { + sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s", + procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch + ); + } + } + return bRet; +} + +#endif + +/********************************************** + osl_getProcessInfo + *********************************************/ + +oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo) +{ + pid_t pid; + + if (Process == NULL) + pid = getpid(); + else + pid = ((oslProcessImpl*)Process)->m_pid; + + if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo))) + return osl_Process_E_Unknown; + + pInfo->Fields = 0; + + if (Fields & osl_Process_IDENTIFIER) + { + pInfo->Ident = pid; + pInfo->Fields |= osl_Process_IDENTIFIER; + } + + if (Fields & osl_Process_EXITCODE) + { + if ((Process != NULL) && + osl_checkCondition(((oslProcessImpl*)Process)->m_terminated)) + { + pInfo->Code = ((oslProcessImpl*)Process)->m_status; + pInfo->Fields |= osl_Process_EXITCODE; + } + } + + if (Fields & (osl_Process_HEAPUSAGE | osl_Process_CPUTIMES)) + { + +#if defined(SOLARIS) + + int fd; + sal_Char name[PATH_MAX + 1]; + + snprintf(name, sizeof(name), "/proc/%u", pid); + + if ((fd = open(name, O_RDONLY)) >= 0) + { + prstatus_t prstatus; + + if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0) + { + if (Fields & osl_Process_CPUTIMES) + { + pInfo->UserTime.Seconds = prstatus.pr_utime.tv_sec; + pInfo->UserTime.Nanosec = prstatus.pr_utime.tv_nsec; + pInfo->SystemTime.Seconds = prstatus.pr_stime.tv_sec; + pInfo->SystemTime.Nanosec = prstatus.pr_stime.tv_nsec; + + pInfo->Fields |= osl_Process_CPUTIMES; + } + + if (Fields & osl_Process_HEAPUSAGE) + { + pInfo->HeapUsage = prstatus.pr_brksize; + + pInfo->Fields |= osl_Process_HEAPUSAGE; + } + + close(fd); + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; + } + else + close(fd); + } + +#elif defined(HPUX) + + struct pst_status prstatus; + + if (pstat_getproc(&prstatus, sizeof(prstatus), (size_t)0, pid) == 1) + { + if (Fields & osl_Process_CPUTIMES) + { + pInfo->UserTime.Seconds = prstatus.pst_utime; + pInfo->UserTime.Nanosec = 500000L; + pInfo->SystemTime.Seconds = prstatus.pst_stime; + pInfo->SystemTime.Nanosec = 500000L; + + pInfo->Fields |= osl_Process_CPUTIMES; + } + + if (Fields & osl_Process_HEAPUSAGE) + { + pInfo->HeapUsage = prstatus.pst_vdsize*PAGESIZE; + + pInfo->Fields |= osl_Process_HEAPUSAGE; + } + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; + } + +#elif defined(LINUX) + + if ( (Fields & osl_Process_CPUTIMES) || (Fields & osl_Process_HEAPUSAGE) ) + { + struct osl_procStat procstat; + memset(&procstat,0,sizeof(procstat)); + + if ( (Fields & osl_Process_CPUTIMES) && osl_getProcStat(pid, &procstat) ) + { + /* + * mfe: + * We calculate only time of the process proper. + * Threads are processes, we do not consider their time here! + * (For this, cutime and cstime should be used, it seems not + * to work in 2.0.36) + */ + + long clktck; + unsigned long hz; + unsigned long userseconds; + unsigned long systemseconds; + + clktck = sysconf(_SC_CLK_TCK); + if (clktck < 0) { + return osl_Process_E_Unknown; + } + hz = (unsigned long) clktck; + + userseconds = procstat.utime/hz; + systemseconds = procstat.stime/hz; + + pInfo->UserTime.Seconds = userseconds; + pInfo->UserTime.Nanosec = procstat.utime - (userseconds * hz); + pInfo->SystemTime.Seconds = systemseconds; + pInfo->SystemTime.Nanosec = procstat.stime - (systemseconds * hz); + + pInfo->Fields |= osl_Process_CPUTIMES; + } + + if ( (Fields & osl_Process_HEAPUSAGE) && osl_getProcStatus(pid, &procstat) ) + { + /* + * mfe: + * vm_data (found in status) shows the size of the data segment + * it a rough approximation of the core heap size + */ + pInfo->HeapUsage = procstat.vm_data*1024; + + pInfo->Fields |= osl_Process_HEAPUSAGE; + } + } + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; +#endif + + } + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; +} + + +/*********************************************** + helper function for osl_joinProcessWithTimeout + **********************************************/ + +static int is_timeout(const struct timeval* tend) +{ + struct timeval tcurrent; + gettimeofday(&tcurrent, NULL); + return (tcurrent.tv_sec >= tend->tv_sec); +} + +/********************************************** + kill(pid, 0) is usefull for checking if a + process is still alive, but remember that + kill even returns 0 if the process is already + a zombie. + *********************************************/ + +static int is_process_dead(pid_t pid) +{ + return ((-1 == kill(pid, 0)) && (ESRCH == errno)); +} + +/********************************************** + osl_joinProcessWithTimeout + *********************************************/ + +oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout) +{ + oslProcessImpl* pChild = ChildList; + oslProcessError osl_error = osl_Process_E_None; + + OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter"); + OSL_ASSERT(ChildListMutex); + + if (NULL == Process || 0 == ChildListMutex) + return osl_Process_E_Unknown; + + osl_acquireMutex(ChildListMutex); + + /* check if process is a child of ours */ + while (pChild != NULL) + { + if (pChild == (oslProcessImpl*)Process) + break; + + pChild = pChild->m_pnext; + } + + osl_releaseMutex(ChildListMutex); + + if (pChild != NULL) + { + oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout); + + if (osl_cond_result_timeout == cond_res) + osl_error = osl_Process_E_TimedOut; + else if (osl_cond_result_ok != cond_res) + osl_error = osl_Process_E_Unknown; + } + else /* alien process; StatusThread will not be able + to set the condition terminated */ + { + pid_t pid = ((oslProcessImpl*)Process)->m_pid; + + if (pTimeout) + { + int timeout = 0; + struct timeval tend; + + gettimeofday(&tend, NULL); + + tend.tv_sec += pTimeout->Seconds; + + while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0)) + sleep(1); + + if (timeout) + osl_error = osl_Process_E_TimedOut; + } + else /* infinite */ + { + while (!is_process_dead(pid)) + sleep(1); + } + } + return osl_error; +} + +/********************************************** + osl_joinProcess + *********************************************/ + +oslProcessError SAL_CALL osl_joinProcess(oslProcess Process) +{ + return osl_joinProcessWithTimeout(Process, NULL); +} diff --git a/sal/osl/unx/process_impl.cxx b/sal/osl/unx/process_impl.cxx new file mode 100644 index 000000000000..e712b6748e7f --- /dev/null +++ b/sal/osl/unx/process_impl.cxx @@ -0,0 +1,412 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "osl/process.h" + +#ifndef INCLUDED_LIMITS_H +#include <limits.h> +#define INCLUDED_LIMITS_H +#endif + +#ifndef INCLUDED_PTHREAD_H +#include <pthread.h> +#define INCLUDED_PTHREAD_H +#endif + +#ifndef INCLUDED_STDLIB_H +#include <stdlib.h> +#define INCLUDED_STDLIB_H +#endif + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif +#include "osl/diagnose.h" +#include <osl/file.h> +#include "osl/module.h" +#include "osl/thread.h" +#include "rtl/ustring.hxx" + +#ifndef _OSL_FILE_PATH_HELPER_H_ +#include "file_path_helper.h" +#endif + +#ifndef _OSL_UUNXAPI_H_ +#include "uunxapi.h" +#endif + +/*************************************** + osl_bootstrap_getExecutableFile_Impl(). + + @internal + @see rtl_bootstrap + @see #i37371# + + **************************************/ + +extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C(); + + +#if defined(MACOSX) +#include <mach-o/dyld.h> + +oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C() +{ + oslProcessError result = osl_Process_E_NotFound; + + char buffer[PATH_MAX]; + size_t buflen = sizeof(buffer); + +#if __GNUC__ >= 4 && defined(MACOSX) + if (_NSGetExecutablePath (buffer, (uint32_t*)&buflen) == 0) +#else + if (_NSGetExecutablePath (buffer, &buflen) == 0) +#endif + { + /* Determine absolute path. */ + char abspath[PATH_MAX]; + if (realpath (buffer, abspath) != 0) + { + /* Convert from utf8 to unicode. */ + rtl_uString * pAbsPath = 0; + rtl_string2UString ( + &(pAbsPath), + abspath, rtl_str_getLength (abspath), + RTL_TEXTENCODING_UTF8, + OSTRING_TO_OUSTRING_CVTFLAGS); + + if (pAbsPath) + { + /* Convert from path to url. */ + if (osl_getFileURLFromSystemPath (pAbsPath, ppFileURL) == osl_File_E_None) + { + /* Success. */ + result = osl_Process_E_None; + } + rtl_uString_release (pAbsPath); + } + } + } + + return (result); +} + +#elif !defined(NO_DL_FUNCTIONS) +#include <dlfcn.h> + +oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C() +{ + oslProcessError result = osl_Process_E_NotFound; + + /* Determine address of "main()" function. */ + void * addr = dlsym (RTLD_DEFAULT, "main"); + if (addr != 0) + { + /* Determine module URL. */ + if (osl_getModuleURLFromAddress (addr, ppFileURL)) + { + /* Success. */ + result = osl_Process_E_None; + } + } + + return (result); +} + +#else /* NO_DL_FUNCTIONS */ + +oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C() +{ + /* Fallback to ordinary osl_getExecutableFile(). */ + return osl_getExecutableFile (ppFileURL); +} + +#endif /* NO_DL_FUNCTIONS */ + +/*************************************** + CommandArgs_Impl. + **************************************/ +struct CommandArgs_Impl +{ + pthread_mutex_t m_mutex; + sal_uInt32 m_nCount; + rtl_uString ** m_ppArgs; +}; + +static struct CommandArgs_Impl g_command_args = +{ + PTHREAD_MUTEX_INITIALIZER, + 0, + 0 +}; + +/*************************************** + osl_getExecutableFile(). + **************************************/ +oslProcessError SAL_CALL osl_getExecutableFile (rtl_uString ** ppustrFile) +{ + oslProcessError result = osl_Process_E_NotFound; + + pthread_mutex_lock (&(g_command_args.m_mutex)); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > 0) + { + /* CommandArgs set. Obtain argv[0]. */ + rtl_uString_assign (ppustrFile, g_command_args.m_ppArgs[0]); + result = osl_Process_E_None; + } + pthread_mutex_unlock (&(g_command_args.m_mutex)); + + return (result); +} + +/*************************************** + osl_getCommandArgCount(). + **************************************/ +sal_uInt32 SAL_CALL osl_getCommandArgCount (void) +{ + sal_uInt32 result = 0; + + pthread_mutex_lock (&(g_command_args.m_mutex)); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > 0) + result = g_command_args.m_nCount - 1; + pthread_mutex_unlock (&(g_command_args.m_mutex)); + + return (result); +} + +/*************************************** + osl_getCommandArg(). + **************************************/ +oslProcessError SAL_CALL osl_getCommandArg (sal_uInt32 nArg, rtl_uString ** strCommandArg) +{ + oslProcessError result = osl_Process_E_NotFound; + + pthread_mutex_lock (&(g_command_args.m_mutex)); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > (nArg + 1)) + { + rtl_uString_assign (strCommandArg, g_command_args.m_ppArgs[nArg + 1]); + result = osl_Process_E_None; + } + pthread_mutex_unlock (&(g_command_args.m_mutex)); + + return (result); +} + +/*************************************** + osl_setCommandArgs(). + **************************************/ +void SAL_CALL osl_setCommandArgs (int argc, char ** argv) +{ + OSL_ASSERT(argc > 0); + pthread_mutex_lock (&(g_command_args.m_mutex)); + OSL_ENSURE (g_command_args.m_nCount == 0, "osl_setCommandArgs(): CommandArgs already set."); + if (g_command_args.m_nCount == 0) + { + rtl_uString** ppArgs = (rtl_uString**)rtl_allocateZeroMemory (argc * sizeof(rtl_uString*)); + if (ppArgs != 0) + { + rtl_TextEncoding encoding = osl_getThreadTextEncoding(); + for (int i = 0; i < argc; i++) + { + rtl_string2UString ( + &(ppArgs[i]), + argv[i], rtl_str_getLength (argv[i]), encoding, + OSTRING_TO_OUSTRING_CVTFLAGS); + } + if (ppArgs[0] != 0) + { + /* see @ osl_getExecutableFile(). */ + if (rtl_ustr_indexOfChar (rtl_uString_getStr(ppArgs[0]), sal_Unicode('/')) == -1) + { + const rtl::OUString PATH (RTL_CONSTASCII_USTRINGPARAM("PATH")); + + rtl_uString * pSearchPath = 0; + osl_getEnvironment (PATH.pData, &pSearchPath); + if (pSearchPath) + { + rtl_uString * pSearchResult = 0; + osl_searchPath (ppArgs[0], pSearchPath, &pSearchResult); + if (pSearchResult) + { + rtl_uString_assign (&(ppArgs[0]), pSearchResult); + rtl_uString_release (pSearchResult); + } + rtl_uString_release (pSearchPath); + } + } + + rtl_uString * pArg0 = 0; + if (realpath_u (ppArgs[0], &pArg0)) + { + osl_getFileURLFromSystemPath (pArg0, &(ppArgs[0])); + rtl_uString_release (pArg0); + } + } + g_command_args.m_nCount = argc; + g_command_args.m_ppArgs = ppArgs; + } + } + pthread_mutex_unlock (&(g_command_args.m_mutex)); +} + +/*************************************** + osl_getEnvironment(). + **************************************/ +oslProcessError SAL_CALL osl_getEnvironment(rtl_uString* pustrEnvVar, rtl_uString** ppustrValue) +{ + oslProcessError result = osl_Process_E_NotFound; + rtl_TextEncoding encoding = osl_getThreadTextEncoding(); + rtl_String* pstr_env_var = 0; + + OSL_PRECOND(pustrEnvVar, "osl_getEnvironment(): Invalid parameter"); + OSL_PRECOND(ppustrValue, "osl_getEnvironment(): Invalid parameter"); + + rtl_uString2String( + &pstr_env_var, + rtl_uString_getStr(pustrEnvVar), rtl_uString_getLength(pustrEnvVar), encoding, + OUSTRING_TO_OSTRING_CVTFLAGS); + if (pstr_env_var != 0) + { + const char* p_env_var = getenv (rtl_string_getStr (pstr_env_var)); + if (p_env_var != 0) + { + rtl_string2UString( + ppustrValue, + p_env_var, strlen(p_env_var), encoding, + OSTRING_TO_OUSTRING_CVTFLAGS); + OSL_ASSERT(*ppustrValue != NULL); + + result = osl_Process_E_None; + } + rtl_string_release(pstr_env_var); + } + + return (result); +} + +/*************************************** + osl_getProcessWorkingDir(). + **************************************/ +oslProcessError SAL_CALL osl_getProcessWorkingDir(rtl_uString **ppustrWorkingDir) +{ + oslProcessError result = osl_Process_E_Unknown; + char buffer[PATH_MAX]; + + OSL_PRECOND(ppustrWorkingDir, "osl_getProcessWorkingDir(): Invalid parameter"); + + if (getcwd (buffer, sizeof(buffer)) != 0) + { + rtl_uString* ustrTmp = 0; + + rtl_string2UString( + &ustrTmp, + buffer, strlen(buffer), osl_getThreadTextEncoding(), + OSTRING_TO_OUSTRING_CVTFLAGS); + if (ustrTmp != 0) + { + if (osl_getFileURLFromSystemPath (ustrTmp, ppustrWorkingDir) == osl_File_E_None) + result = osl_Process_E_None; + rtl_uString_release (ustrTmp); + } + } + + return (result); +} + +/****************************************************************************** + * + * new functions to set/return the current process locale + * + *****************************************************************************/ + +struct ProcessLocale_Impl +{ + pthread_mutex_t m_mutex; + rtl_Locale * m_pLocale; +}; + +static struct ProcessLocale_Impl g_process_locale = +{ + PTHREAD_MUTEX_INITIALIZER, + 0 +}; + +extern "C" void _imp_getProcessLocale( rtl_Locale ** ); +extern "C" int _imp_setProcessLocale( rtl_Locale * ); + +/********************************************** + osl_getProcessLocale(). + *********************************************/ +oslProcessError SAL_CALL osl_getProcessLocale( rtl_Locale ** ppLocale ) +{ + OSL_PRECOND(ppLocale, "osl_getProcessLocale(): Invalid parameter."); + + pthread_mutex_lock(&(g_process_locale.m_mutex)); + + if (g_process_locale.m_pLocale == 0) + _imp_getProcessLocale (&(g_process_locale.m_pLocale)); + *ppLocale = g_process_locale.m_pLocale; + + pthread_mutex_unlock (&(g_process_locale.m_mutex)); + + return (osl_Process_E_None); +} + +/********************************************** + osl_setProcessLocale(). + *********************************************/ +oslProcessError SAL_CALL osl_setProcessLocale( rtl_Locale * pLocale ) +{ + oslProcessError result = osl_Process_E_Unknown; + + OSL_PRECOND(pLocale, "osl_setProcessLocale(): Invalid parameter."); + + pthread_mutex_lock(&(g_process_locale.m_mutex)); + if (_imp_setProcessLocale (pLocale) == 0) + { + g_process_locale.m_pLocale = pLocale; + result = osl_Process_E_None; + } + pthread_mutex_unlock (&(g_process_locale.m_mutex)); + + return (result); +} diff --git a/sal/osl/unx/procimpl.h b/sal/osl/unx/procimpl.h new file mode 100644 index 000000000000..1a08d72ffe5a --- /dev/null +++ b/sal/osl/unx/procimpl.h @@ -0,0 +1,50 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_PROCIMPL_H_ +#define _OSL_PROCIMPL_H_ + +#include <osl/process.h> +#include <osl/conditn.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _oslProcessImpl { + pid_t m_pid; + oslCondition m_terminated; + int m_status; + struct _oslProcessImpl* m_pnext; +} oslProcessImpl; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/unx/profile.c b/sal/osl/unx/profile.c new file mode 100644 index 000000000000..c77a27543261 --- /dev/null +++ b/sal/osl/unx/profile.c @@ -0,0 +1,2221 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/profile.h> +#include <osl/process.h> +#include <osl/thread.h> +#include <rtl/alloc.h> +#include <osl/util.h> + +#define LINES_INI 32 +#define LINES_ADD 10 +#define SECTIONS_INI 5 +#define SECTIONS_ADD 3 +#define ENTRIES_INI 5 +#define ENTRIES_ADD 3 + + +#define STR_INI_EXTENSION "rc" +#define STR_INI_METAHOME "?~" +#define STR_INI_METASYS "?$" +#define STR_INI_METACFG "?^" +#define STR_INI_METAINS "?#" + +#define STR_INI_BOOLYES "yes" +#define STR_INI_BOOLON "on" +#define STR_INI_BOOLONE "1" +#define STR_INI_BOOLNO "no" +#define STR_INI_BOOLOFF "off" +#define STR_INI_BOOLZERO "0" + +#define FLG_USER 0x00FF +#define FLG_AUTOOPEN 0x0100 +#define FLG_MODIFIED 0x0200 + +#define SVERSION_LOCATION STR_INI_METACFG +#define SVERSION_FALLBACK STR_INI_METASYS +#define SVERSION_NAME "sversion" +#define SVERSION_SECTION "Versions" +#define SVERSION_SOFFICE "StarOffice" +#define SVERSION_PROFILE "sofficerc" +#define SVERSION_OPTION "userid:" +#define SVERSION_DIRS { "bin", "program" } +#define SVERSION_USER "user" + +#define DEFAULT_PMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) + +#define _BUILD_STR_(n) # n +#define BUILD_STR(n) _BUILD_STR_(n) + + +/*#define DEBUG_OSL_PROFILE*/ +/*#define TRACE_OSL_PROFILE*/ + +/*****************************************************************************/ +/* Data Type Definition */ +/*****************************************************************************/ + +typedef time_t osl_TStamp; + +typedef enum _osl_TLockMode +{ + un_lock, read_lock, write_lock +} osl_TLockMode; + +typedef struct _osl_TFile +{ + int m_Handle; + sal_Char* m_pReadPtr; + sal_Char m_ReadBuf[512]; + sal_Char* m_pWriteBuf; + sal_uInt32 m_nWriteBufLen; + sal_uInt32 m_nWriteBufFree; +} osl_TFile; + +typedef struct _osl_TProfileEntry +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; +} osl_TProfileEntry; + +typedef struct _osl_TProfileSection +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; + sal_uInt32 m_NoEntries; + sal_uInt32 m_MaxEntries; + osl_TProfileEntry* m_Entries; +} osl_TProfileSection; + + +/* + Profile-data structure hidden behind oslProfile: +*/ +typedef struct _osl_TProfileImpl +{ + sal_uInt32 m_Flags; + osl_TFile* m_pFile; + osl_TStamp m_Stamp; + sal_Char m_FileName[PATH_MAX + 1]; + sal_uInt32 m_NoLines; + sal_uInt32 m_MaxLines; + sal_uInt32 m_NoSections; + sal_uInt32 m_MaxSections; + sal_Char** m_Lines; + osl_TProfileSection* m_Sections; + pthread_mutex_t m_AccessLock; + sal_Bool m_bIsValid; +} osl_TProfileImpl; + + +/*****************************************************************************/ +/* Static Module Function Declarations */ +/*****************************************************************************/ + +static osl_TFile* openFileImpl(const sal_Char* pszFilename, oslProfileOption ProfileFlags); +static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags); +static sal_Bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode); +static sal_Bool OslProfile_rewindFile(osl_TFile* pFile, sal_Bool bTruncate); +static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile); + +static sal_Char* OslProfile_getLine(osl_TFile* pFile); +static sal_Bool OslProfile_putLine(osl_TFile* pFile, const sal_Char *pszLine); +static sal_Char* stripBlanks(sal_Char* String, sal_uInt32* pLen); +static sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line); +static sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo); +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo); +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + sal_Char* Entry, sal_uInt32 Len); +static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, sal_Char* Entry, sal_uInt32 Len); +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry); +static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len); +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection); +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section, + const sal_Char* Entry, sal_uInt32 *pNoEntry); +static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile); +static sal_Bool storeProfile(osl_TProfileImpl* pProfile, sal_Bool bCleanup); +static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable); +static sal_Bool releaseProfile(osl_TProfileImpl* pProfile); + +static sal_Bool writeProfileImpl (osl_TFile* pFile); +static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl*); +static sal_Bool osl_ProfileSwapProfileNames(osl_TProfileImpl*); +static void osl_ProfileGenerateExtension(sal_Char* pszFileName, sal_Char* pszExtension, sal_Char* pszTmpName); +static oslProfile SAL_CALL osl_psz_openProfile(const sal_Char *pszProfileName, oslProfileOption Flags); + +/* implemented in file.c */ +extern oslFileError FileURLToPath( char *, size_t, rtl_uString* ); + +/*****************************************************************************/ +/* Exported Module Functions */ +/*****************************************************************************/ +oslProfile SAL_CALL osl_openProfile(rtl_uString *ustrProfileName, oslProfileOption Options) +{ + char profilePath[PATH_MAX] = ""; + + if ( ustrProfileName != 0 && ustrProfileName->buffer[0] != 0 ) + FileURLToPath( profilePath, PATH_MAX, ustrProfileName ); + + return osl_psz_openProfile( profilePath,Options ); +} + + +static oslProfile SAL_CALL osl_psz_openProfile(const sal_Char *pszProfileName, oslProfileOption Flags) +{ + osl_TFile* pFile; + osl_TProfileImpl* pProfile; + sal_Char Filename[PATH_MAX]; + sal_Bool bRet = sal_False; + + Filename[0] = '\0'; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_openProfile\n"); +#endif + +#ifdef DEBUG_OSL_PROFILE + Flags=osl_Profile_FLUSHWRITE; + + OSL_TRACE("opening '%s'\n",pszProfileName); + if ( Flags == osl_Profile_DEFAULT ) + { + OSL_TRACE("with osl_Profile_DEFAULT\n"); + } + if ( Flags & osl_Profile_SYSTEM ) + { + OSL_TRACE("with osl_Profile_SYSTEM\n"); + } + if ( Flags & osl_Profile_READLOCK ) + { + OSL_TRACE("with osl_Profile_READLOCK\n"); + } + if ( Flags & osl_Profile_WRITELOCK ) + { + OSL_TRACE("with osl_Profile_WRITELOCK\n"); + } + if ( Flags & osl_Profile_FLUSHWRITE ) + { + OSL_TRACE("with osl_Profile_FLUSHWRITE\n"); + } +#endif + + + if ( ( pFile = openFileImpl(pszProfileName, Flags ) ) == NULL ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_openProfile [not opened]\n"); +#endif + return (NULL); + } + + + pProfile = (osl_TProfileImpl*)calloc(1, sizeof(osl_TProfileImpl)); + + if ( pProfile == 0 ) + { + return 0; + } + + pProfile->m_Flags = Flags & FLG_USER; + + if ( Flags & ( osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) ) + { + pProfile->m_pFile = pFile; + } + + pthread_mutex_init(&(pProfile->m_AccessLock),PTHREAD_MUTEXATTR_DEFAULT); + pProfile->m_bIsValid=sal_True; + + pProfile->m_Stamp = OslProfile_getFileStamp(pFile); + bRet=loadProfile(pFile, pProfile); + bRet &= realpath(pszProfileName, pProfile->m_FileName) != NULL; + OSL_ASSERT(bRet); + + if (pProfile->m_pFile == NULL) + closeFileImpl(pFile,pProfile->m_Flags); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_openProfile [ok]\n"); +#endif + return (pProfile); +} + +sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_closeProfile\n"); +#endif + + if ( Profile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [profile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pProfile->m_AccessLock)); + + if ( pProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pProfile->m_bIsValid); + pthread_mutex_unlock(&(pProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [not valid]\n"); +#endif + return sal_False; + } + + pProfile->m_bIsValid=sal_False; + + if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) && ( pProfile->m_Flags & FLG_MODIFIED ) ) + { + pProfile = acquireProfile(Profile,sal_True); + + if ( pProfile != 0 ) + { + bRet=storeProfile(pProfile, sal_True); + OSL_ASSERT(bRet); + } + } + else + { + pProfile = acquireProfile(Profile,sal_False); + } + + + if ( pProfile == 0 ) + { + pthread_mutex_unlock(&(pProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [pProfile==0]\n"); +#endif + return sal_False; + } + + if (pProfile->m_pFile != NULL) + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + + pProfile->m_pFile = NULL; + pProfile->m_FileName[0] = '\0'; + + /* release whole profile data types memory */ + if ( pProfile->m_NoLines > 0) + { + unsigned int idx=0; + if ( pProfile->m_Lines != 0 ) + { + for ( idx = 0 ; idx < pProfile->m_NoLines ; ++idx) + { + if ( pProfile->m_Lines[idx] != 0 ) + { + free(pProfile->m_Lines[idx]); + pProfile->m_Lines[idx]=0; + } + } + free(pProfile->m_Lines); + pProfile->m_Lines=0; + } + if ( pProfile->m_Sections != 0 ) + { + /*osl_TProfileSection* pSections=pProfile->m_Sections;*/ + for ( idx = 0 ; idx < pProfile->m_NoSections ; ++idx ) + { + if ( pProfile->m_Sections[idx].m_Entries != 0 ) + { + free(pProfile->m_Sections[idx].m_Entries); + pProfile->m_Sections[idx].m_Entries=0; + } + } + free(pProfile->m_Sections); + pProfile->m_Sections=0; + } + } + + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + + pthread_mutex_destroy(&(pProfile->m_AccessLock)); + + free(pProfile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [ok]\n"); +#endif + return (sal_True); +} + + +sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*) Profile; + osl_TFile* pFile; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_flushProfile()\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [pProfile == 0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pProfile->m_AccessLock)); + + if ( pProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pProfile->m_bIsValid); + pthread_mutex_unlock(&(pProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile [not valid]\n"); +#endif + return sal_False; + } + + pFile = pProfile->m_pFile; + if ( !( pFile != 0 && pFile->m_Handle >= 0 ) ) + { + pthread_mutex_unlock(&(pProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [invalid file]\n"); +#endif + return sal_False; + } + + if ( pProfile->m_Flags & FLG_MODIFIED ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("swapping to storeprofile\n"); +#endif + bRet = storeProfile(pProfile,sal_False); + OSL_ASSERT(bRet); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [ok]\n"); +#endif + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + return bRet; +} + +static sal_Bool writeProfileImpl(osl_TFile* pFile) +{ + int BytesWritten=0; +#if OSL_DEBUG_LEVEL > 1 + unsigned int nLen=0; +#endif + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileImpl()\n"); +#endif + + if ( !( pFile != 0 && pFile->m_Handle >= 0 ) || ( pFile->m_pWriteBuf == 0 ) ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileImpl() [invalid args]\n"); +#endif + return sal_False; + } + +#if OSL_DEBUG_LEVEL > 1 + nLen=strlen(pFile->m_pWriteBuf); + OSL_ASSERT(nLen == (pFile->m_nWriteBufLen - pFile->m_nWriteBufFree)); +#endif + + BytesWritten = write(pFile->m_Handle, pFile->m_pWriteBuf, pFile->m_nWriteBufLen - pFile->m_nWriteBufFree); + + if ( BytesWritten <= 0 ) + { + OSL_TRACE("write failed '%s'\n",strerror(errno)); + return (sal_False); + } + +#if OSL_DEBUG_LEVEL > 1 + OSL_ASSERT( + BytesWritten >= 0 && SAL_INT_CAST(unsigned int, BytesWritten) == nLen); +#endif + + free(pFile->m_pWriteBuf); + pFile->m_pWriteBuf=0; + pFile->m_nWriteBufLen=0; + pFile->m_nWriteBufFree=0; +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileImpl() [ok]\n"); +#endif + return sal_True; +} + + +sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Char* pszString, sal_uInt32 MaxLen, + const sal_Char* pszDefault) +{ + sal_uInt32 NoEntry; + sal_Char* pStr=0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile=0; + osl_TProfileImpl* pTmpProfile=0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileString\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pTmpProfile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pProfile->m_bIsValid); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [not valid]\n"); +#endif + return sal_False; + } + + pProfile = acquireProfile(Profile, sal_False); + + if ( pProfile == NULL ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pProfile==0]\n"); +#endif + return (sal_False); + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) && + (NoEntry < pSec->m_NoEntries) && + ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line], + '=')) != NULL)) + { + pStr++; + } + else + { + pStr=(sal_Char*)pszDefault; + } + + if ( pStr != 0 ) + { + pStr = stripBlanks(pStr, NULL); + MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr); + pStr = stripBlanks(pStr, &MaxLen); + strncpy(pszString, pStr, MaxLen); + pszString[MaxLen] = '\0'; + } + } + else + { /* not implemented */ } + + + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + if ( pStr == 0 ) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pStr==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [ok]\n"); +#endif + + return (sal_True); +} + + +sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Bool Default) +{ + sal_Char Line[32]; + Line[0] = '\0'; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileBool\n"); +#endif + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + if ((strcasecmp(Line, STR_INI_BOOLYES) == 0) || + (strcasecmp(Line, STR_INI_BOOLON) == 0) || + (strcasecmp(Line, STR_INI_BOOLONE) == 0)) + Default = sal_True; + else + if ((strcasecmp(Line, STR_INI_BOOLNO) == 0) || + (strcasecmp(Line, STR_INI_BOOLOFF) == 0) || + (strcasecmp(Line, STR_INI_BOOLZERO) == 0)) + Default = sal_False; + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileBool [ok]\n"); +#endif + + return (Default); +} + + +sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_uInt32 FirstId, const sal_Char* Strings[], + sal_uInt32 Default) +{ + sal_uInt32 i; + sal_Char Line[256]; + Line[0] = '\0'; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileIdent\n"); +#endif + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + i = 0; + while (Strings[i] != NULL) + { + if (strcasecmp(Line, Strings[i]) == 0) + { + Default = i + FirstId; + break; + } + i++; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileIdent [ok]\n"); +#endif + return (Default); +} + +sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + const sal_Char* pszString) +{ + sal_uInt32 i; + sal_Bool bRet = sal_False; + sal_uInt32 NoEntry; + sal_Char* pStr; + sal_Char* Line = 0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + osl_TProfileImpl* pTmpProfile = 0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileString\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [pTmpProfile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pTmpProfile->m_bIsValid); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not valid]\n"); +#endif + return sal_False; + } + + pProfile=acquireProfile(Profile, sal_True); + + if (pProfile == NULL) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [pProfile==0]\n"); +#endif + return (sal_False); + } + + Line = (sal_Char*) malloc(strlen(pszEntry)+strlen(pszString)+48); + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == NULL) + { + Line[0] = '\0'; + addLine(pProfile, Line); + + Line[0] = '['; + strcpy(&Line[1], pszSection); + Line[1 + strlen(pszSection)] = ']'; + Line[2 + strlen(pszSection)] = '\0'; + + if (((pStr = addLine(pProfile, Line)) == NULL) || + (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection)))) + { + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + free(Line); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not added]\n"); +#endif + return (sal_False); + } + + pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1]; + NoEntry = pSec->m_NoEntries; + } + + Line[0] = '\0'; + strcpy(&Line[0], pszEntry); + Line[0 + strlen(pszEntry)] = '='; + strcpy(&Line[1 + strlen(pszEntry)], pszString); + + if (NoEntry >= pSec->m_NoEntries) + { + if (pSec->m_NoEntries > 0) + i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1; + else + i = pSec->m_Line + 1; + + if (((pStr = insertLine(pProfile, Line, i)) == NULL) || + (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry)))) + { + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + free(Line); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not inserted]\n"); +#endif + return (sal_False); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + else + { + i = pSec->m_Entries[NoEntry].m_Line; + free(pProfile->m_Lines[i]); + pProfile->m_Lines[i] = strdup(Line); + setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry)); + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else { + /* not implemented */ + } + + bRet = releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + if ( Line!= 0 ) + { + free(Line); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [ok]\n"); +#endif + + return bRet; +} + + +sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Bool Value) +{ + sal_Bool bRet=sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileBool\n"); +#endif + + if (Value) + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE); + else + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileBool [ok]\n"); +#endif + + return bRet; +} + + +sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_uInt32 FirstId, const sal_Char* Strings[], + sal_uInt32 Value) +{ + int i, n; + sal_Bool bRet=sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileIdent\n"); +#endif + + for (n = 0; Strings[n] != NULL; n++); + + if ((i = Value - FirstId) >= n) + bRet=sal_False; + else + bRet = osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileIdent\n"); +#endif + return bRet; +} + + +sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile, + const sal_Char *pszSection, const sal_Char *pszEntry) +{ + sal_uInt32 NoEntry; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + osl_TProfileImpl* pTmpProfile = 0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_removeProfileEntry\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [pProfile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pTmpProfile->m_bIsValid); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [not valid]\n"); +#endif + return sal_False; + } + + + pProfile = acquireProfile(Profile, sal_True); + + if (pProfile == NULL) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [pProfile==0]\n"); +#endif + return (sal_False); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) && + (NoEntry < pSec->m_NoEntries)) + { + removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line); + removeEntry(pSec, NoEntry); + if (pSec->m_NoEntries == 0) + { + removeLine(pProfile, pSec->m_Line); + + /* remove any empty separation line */ + if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0')) + removeLine(pProfile, pSec->m_Line - 1); + + removeSection(pProfile, pSec); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else + { /* not implemented */ } + + + bRet = releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [ok]\n"); +#endif + return bRet; +} + + +sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile, const sal_Char *pszSection, + sal_Char* pszBuffer, sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + sal_uInt32 NoEntry; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + osl_TProfileImpl* pTmpProfile = 0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_getProfileSectionEntries\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [pTmpProfile==0]\n"); +#endif + return sal_False; + + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pTmpProfile->m_bIsValid); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [not valid]\n"); +#endif + + return sal_False; + } + + pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [pProfile=0]\n"); +#endif + + return (0); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != NULL) + { + if (MaxLen != 0) + { + for (i = 0; i < pSec->m_NoEntries; i++) + { + if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len); + n += pSec->m_Entries[i].m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pSec->m_NoEntries; i++) + n += pSec->m_Entries[i].m_Len + 1; + + n += 1; + } + } + else + n = 0; + } + else { + /* not implemented */ + } + + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [ok]\n"); +#endif + + return (n); +} + +sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile, sal_Char* pszBuffer, sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + osl_TProfileImpl* pTmpProfile = 0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_getProfileSections\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSections [pTmpProfile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pTmpProfile->m_bIsValid); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSections [not valid]\n"); +#endif + return sal_False; + } + + pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSections [pProfile==0]\n"); +#endif + return (0); + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (MaxLen != 0) + { + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if ((n + pSec->m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], + pSec->m_Len); + n += pSec->m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pProfile->m_NoSections; i++) + n += pProfile->m_Sections[i].m_Len + 1; + + n += 1; + } + } + else + { /* not implemented */ } + + + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSections [ok]\n"); +#endif + + return (n); +} + +/*****************************************************************************/ +/* Static Module Functions */ +/*****************************************************************************/ + +static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile) +{ + struct stat status; + + if ( (pFile->m_Handle < 0) || (fstat(pFile->m_Handle, &status) < 0) ) + { + return (0); + } + + + return (status.st_mtime); +} + +static sal_Bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode) +{ + struct flock lock; + /* boring hack, but initializers for static vars must be constant */ + static sal_Bool bIsInitialized = sal_False; + static sal_Bool bLockingDisabled; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In OslProfile_lockFile\n"); +#endif + + if ( !bIsInitialized ) + { + sal_Char* pEnvValue; + pEnvValue = getenv( "STAR_PROFILE_LOCKING_DISABLED" ); + + if ( pEnvValue == 0 ) + { + bLockingDisabled = sal_False; + + } + else + { + bLockingDisabled = sal_True; + } + + bIsInitialized = sal_True; + } + + if (pFile->m_Handle < 0) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out OslProfile_lockFile [invalid file handle]\n"); +#endif + return (sal_False); + } + + + if ( bLockingDisabled ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out OslProfile_lockFile [locking disabled]\n"); +#endif + return (sal_True); + } + + + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + switch (eMode) + { + case un_lock: + lock.l_type = F_UNLCK; + break; + + case read_lock: + lock.l_type = F_RDLCK; + break; + + case write_lock: + lock.l_type = F_WRLCK; + break; + } + +#ifndef MACOSX // not MAC OSX + if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 ) +#else + /* Mac OSX will return ENOTSUP for webdav drives so we should ignore it */ + if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 && errno != ENOTSUP ) +#endif /* MACOSX */ + { + OSL_TRACE("fcntl returned -1 (%s)\n",strerror(errno)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out OslProfile_lockFile [fcntl F_SETLKW]\n"); +#endif + return sal_False; + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out OslProfile_lockFile [ok]\n"); +#endif + return sal_True; +} + +static osl_TFile* openFileImpl(const sal_Char* pszFilename, oslProfileOption ProfileFlags ) +{ + int Flags; + osl_TFile* pFile = (osl_TFile*) calloc(1, sizeof(osl_TFile)); + sal_Bool bWriteable = sal_False; + + if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("setting bWriteable to TRUE\n"); +#endif + bWriteable=sal_True; + } + + if (! bWriteable) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("opening '%s' read only\n",pszFilename); +#endif + + pFile->m_Handle = open(pszFilename, O_RDONLY); + /* mfe: argghh!!! do not check if the file could be openend */ + /* default mode expects it that way!!! */ + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("opening '%s' read/write\n",pszFilename); +#endif + if (((pFile->m_Handle = open(pszFilename, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PMODE)) < 0) && + ((pFile->m_Handle = open(pszFilename, O_RDWR)) < 0)) + { + free(pFile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out openFileImpl [open read/write]\n"); +#endif + return (NULL); + } + } + + /* set close-on-exec flag */ + if ((Flags = fcntl(pFile->m_Handle, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + fcntl(pFile->m_Handle, F_SETFD, Flags); + } + + pFile->m_pWriteBuf=0; + pFile->m_nWriteBufFree=0; + pFile->m_nWriteBufLen=0; + + if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("locking '%s' file\n",pszFilename); +#endif + OslProfile_lockFile(pFile, bWriteable ? write_lock : read_lock); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out openFileImpl [ok]\n"); +#endif + return (pFile); +} + +static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags) +{ + osl_TStamp stamp = 0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In closeFileImpl\n"); +#endif + + if ( pFile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out closeFileImpl [pFile == 0]\n"); +#endif + return stamp; + } + + if ( pFile->m_Handle >= 0 ) + { + stamp = OslProfile_getFileStamp(pFile); + + if ( Flags & (osl_Profile_WRITELOCK | osl_Profile_WRITELOCK ) ) + { + OslProfile_lockFile(pFile, un_lock); + } + + close(pFile->m_Handle); + pFile->m_Handle = -1; + } + + + if ( pFile->m_pWriteBuf ) + { + free(pFile->m_pWriteBuf); + } + + free(pFile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out closeFileImpl [ok]\n"); +#endif + + return(stamp); +} + +static sal_Bool OslProfile_rewindFile(osl_TFile* pFile, sal_Bool bTruncate) +{ + sal_Bool bRet = sal_True; +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_OslProfile_rewindFile\n"); +#endif + + if (pFile->m_Handle >= 0) + { + pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("rewinding\n"); +#endif + bRet = (lseek(pFile->m_Handle, SEEK_SET, 0L) == 0L); + + if (bTruncate) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("truncating\n"); +#endif + bRet &= (ftruncate(pFile->m_Handle, 0L) == 0); + } + + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_OslProfile_rewindFile [ok]\n"); +#endif + return bRet; +} + + +static sal_Char* OslProfile_getLine(osl_TFile* pFile) +{ + int Max, Free, Bytes, nLineBytes = 0; + sal_Char* pChr; + sal_Char* pLine = NULL; + sal_Char* pNewLine; + + if ( pFile == 0 ) + { + return 0; + } + + if (pFile->m_Handle < 0) + return NULL; + + do + { + Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf); + + if (Bytes <= 1) + { + /* refill buffer */ + memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes); + pFile->m_pReadPtr = pFile->m_ReadBuf; + + Free = sizeof(pFile->m_ReadBuf) - Bytes; + + if ((Max = read(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free)) < 0) + { + OSL_TRACE("read failed '%s'\n",strerror(errno)); + + if( pLine ) + rtl_freeMemory( pLine ); + pLine = NULL; + break; + } + + if (Max < Free) + { + if ((Max == 0) && ! pLine) + break; + + pFile->m_ReadBuf[Bytes + Max] = '\0'; + } + } + + for (pChr = pFile->m_pReadPtr; + (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') && + (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)); + pChr++); + + Max = pChr - pFile->m_pReadPtr; + pNewLine = (sal_Char*) rtl_allocateMemory( nLineBytes + Max + 1 ); + if( pLine ) + { + memcpy( pNewLine, pLine, nLineBytes ); + rtl_freeMemory( pLine ); + } + memcpy(pNewLine+nLineBytes, pFile->m_pReadPtr, Max); + nLineBytes += Max; + pNewLine[ nLineBytes ] = 0; + pLine = pNewLine; + + if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)) + { + if (*pChr != '\0') + { + if ((pChr[0] == '\r') && (pChr[1] == '\n')) + pChr += 2; + else + pChr += 1; + } + + if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) && + (*pChr == '\0')) + pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + + /* setting Max to -1 indicates terminating read loop */ + Max = -1; + } + + pFile->m_pReadPtr = pChr; + } + while (Max > 0); + + return pLine; +} + +static sal_Bool OslProfile_putLine(osl_TFile* pFile, const sal_Char *pszLine) +{ + unsigned int Len = strlen(pszLine); + +#ifdef DEBUG_OSL_PROFILE + int strLen=0; +#endif + + if ( pFile == 0 || pFile->m_Handle < 0 ) + { + return (sal_False); + } + + if ( pFile->m_pWriteBuf == 0 ) + { + pFile->m_pWriteBuf = (sal_Char*) malloc(Len+3); + pFile->m_nWriteBufLen = Len+3; + pFile->m_nWriteBufFree = Len+3; + } + else + { + if ( pFile->m_nWriteBufFree <= Len + 3 ) + { + sal_Char* pTmp; + + pTmp=(sal_Char*) realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) ); + if ( pTmp == 0 ) + { + return sal_False; + } + pFile->m_pWriteBuf = pTmp; + pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len ); + pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2; + memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree); + } + } + + + + memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1); +#ifdef DEBUG_OSL_PROFILE + strLen = strlen(pFile->m_pWriteBuf); +#endif + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\n'; + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\0'; + + pFile->m_nWriteBufFree-=Len+1; + + return sal_True; +} + +/* platform specific end */ + +static sal_Char* stripBlanks(sal_Char* String, sal_uInt32* pLen) +{ + if ( ( pLen != NULL ) && ( *pLen != 0 ) ) + { + while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t')) + (*pLen)--; + + while ( (*String == ' ') || (*String == '\t') ) + { + String++; + (*pLen)--; + } + } + else + while ( (*String == ' ') || (*String == '\t') ) + String++; + + return (String); +} + +static sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == NULL) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *)); + memset(pProfile->m_Lines,0,pProfile->m_MaxLines * sizeof(sal_Char *)); + } + else + { + unsigned int idx=0; + unsigned int oldmax=pProfile->m_MaxLines; + + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(sal_Char *)); + for ( idx = oldmax ; idx < pProfile->m_MaxLines ; ++idx ) + { + pProfile->m_Lines[idx]=0; + } + } + + if (pProfile->m_Lines == NULL) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return (NULL); + } + + } + + if ( pProfile->m_Lines != 0 && pProfile->m_Lines[pProfile->m_NoLines] != 0 ) + { + free(pProfile->m_Lines[pProfile->m_NoLines]); + } + pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line); + + return (pProfile->m_Lines[pProfile->m_NoLines - 1]); +} + +static sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == NULL) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *)); + memset(pProfile->m_Lines,0,pProfile->m_MaxLines * sizeof(sal_Char *)); + } + else + { + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(sal_Char *)); + + memset(&pProfile->m_Lines[pProfile->m_NoLines], + 0, + (pProfile->m_MaxLines - pProfile->m_NoLines - 1) * sizeof(sal_Char*)); + } + + if (pProfile->m_Lines == NULL) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return (NULL); + } + } + + LineNo = LineNo > pProfile->m_NoLines ? pProfile->m_NoLines : LineNo; + + if (LineNo < pProfile->m_NoLines) + { + sal_uInt32 i, n; + osl_TProfileSection* pSec; + + memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo], + (pProfile->m_NoLines - LineNo) * sizeof(sal_Char *)); + + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line >= LineNo) + pSec->m_Line++; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line >= LineNo) + pSec->m_Entries[n].m_Line++; + } + } + + pProfile->m_NoLines++; + + pProfile->m_Lines[LineNo] = strdup(Line); + + return (pProfile->m_Lines[LineNo]); +} + +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo) +{ + if (LineNo < pProfile->m_NoLines) + { + free(pProfile->m_Lines[LineNo]); + pProfile->m_Lines[LineNo]=0; + if (pProfile->m_NoLines - LineNo > 1) + { + sal_uInt32 i, n; + osl_TProfileSection* pSec; + + memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1], + (pProfile->m_NoLines - LineNo - 1) * sizeof(sal_Char *)); + + memset(&pProfile->m_Lines[pProfile->m_NoLines - 1], + 0, + (pProfile->m_MaxLines - pProfile->m_NoLines) * sizeof(sal_Char*)); + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line > LineNo) + pSec->m_Line--; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line > LineNo) + pSec->m_Entries[n].m_Line--; + } + } + else + { + pProfile->m_Lines[LineNo] = 0; + } + + pProfile->m_NoLines--; + } + + return; +} + +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + sal_Char* Entry, sal_uInt32 Len) +{ + Entry = stripBlanks(Entry, &Len); + pSection->m_Entries[NoEntry].m_Line = Line; + pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line]; + pSection->m_Entries[NoEntry].m_Len = Len; + + return; +} + +static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, sal_Char* Entry, sal_uInt32 Len) +{ + if (pSection != NULL) + { + if (pSection->m_NoEntries >= pSection->m_MaxEntries) + { + if (pSection->m_Entries == NULL) + { + pSection->m_MaxEntries = ENTRIES_INI; + pSection->m_Entries = (osl_TProfileEntry *)malloc( + pSection->m_MaxEntries * sizeof(osl_TProfileEntry)); + } + else + { + pSection->m_MaxEntries += ENTRIES_ADD; + pSection->m_Entries = (osl_TProfileEntry *)realloc(pSection->m_Entries, + pSection->m_MaxEntries * sizeof(osl_TProfileEntry)); + } + + if (pSection->m_Entries == NULL) + { + pSection->m_NoEntries = 0; + pSection->m_MaxEntries = 0; + return (sal_False); + } + } + + pSection->m_NoEntries++; + + Entry = stripBlanks(Entry, &Len); + setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line, + Entry, Len); + + return (sal_True); + } + + return (sal_False); +} + +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry) +{ + if (NoEntry < pSection->m_NoEntries) + { + if (pSection->m_NoEntries - NoEntry > 1) + { + memmove(&pSection->m_Entries[NoEntry], + &pSection->m_Entries[NoEntry + 1], + (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry)); + pSection->m_Entries[pSection->m_NoEntries - 1].m_Line=0; + pSection->m_Entries[pSection->m_NoEntries - 1].m_Offset=0; + pSection->m_Entries[pSection->m_NoEntries - 1].m_Len=0; + } + + pSection->m_NoEntries--; + } + + return; +} + +static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len) +{ + if (pProfile->m_NoSections >= pProfile->m_MaxSections) + { + if (pProfile->m_Sections == NULL) + { + pProfile->m_MaxSections = SECTIONS_INI; + pProfile->m_Sections = (osl_TProfileSection *)malloc(pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + memset(pProfile->m_Sections,0,pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + } + else + { + unsigned int idx=0; + unsigned int oldmax=pProfile->m_MaxSections; + + pProfile->m_MaxSections += SECTIONS_ADD; + pProfile->m_Sections = (osl_TProfileSection *)realloc(pProfile->m_Sections, + pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + for ( idx = oldmax ; idx < pProfile->m_MaxSections ; ++idx ) + { + pProfile->m_Sections[idx].m_Entries=0; + } + } + + if (pProfile->m_Sections == NULL) + { + pProfile->m_NoSections = 0; + pProfile->m_MaxSections = 0; + return (sal_False); + } + } + + pProfile->m_NoSections++; + + if ( pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries != 0 ) + { + free(pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries); + } + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = NULL; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries = 0; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0; + + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line]; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len; + + return (sal_True); +} + +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection) +{ + sal_uInt32 Section; + + if ((Section = pSection - pProfile->m_Sections) < pProfile->m_NoSections) + { + free (pSection->m_Entries); + pSection->m_Entries=0; + if (pProfile->m_NoSections - Section > 1) + { + memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1], + (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection)); + + memset(&pProfile->m_Sections[pProfile->m_NoSections - 1], + 0, + (pProfile->m_MaxSections - pProfile->m_NoSections) * sizeof(osl_TProfileSection)); + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = 0; + } + else + { + pSection->m_Entries = 0; + } + + pProfile->m_NoSections--; + } + + return; +} + +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section, + const sal_Char* Entry, sal_uInt32 *pNoEntry) +{ +static sal_uInt32 Sect = 0; + sal_uInt32 i, n; + sal_uInt32 Len; + const sal_Char* pStr; + osl_TProfileSection* pSec=0; + + Len = strlen(Section); + + n = Sect; + + for (i = 0; i < pProfile->m_NoSections; i++) + { + n %= pProfile->m_NoSections; + pSec = &pProfile->m_Sections[n]; + if ((Len == pSec->m_Len) && + (strncasecmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len) + == 0)) + break; + n++; + } + + Sect = n; + + if (i < pProfile->m_NoSections) + { + Len = strlen(Entry); + + *pNoEntry = pSec->m_NoEntries; + + for (i = 0; i < pSec->m_NoEntries; i++) + { + pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset]; + if ((Len == pSec->m_Entries[i].m_Len) && + (strncasecmp(Entry, pStr, pSec->m_Entries[i].m_Len) + == 0)) + { + *pNoEntry = i; + break; + } + } + } + else + pSec = NULL; + + return (pSec); +} + +static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile) +{ + sal_uInt32 i; + sal_Char* pStr; + sal_Char* pChar; + + sal_Char* pLine; + sal_Char* bWasAdded = NULL; + + pProfile->m_NoLines = 0; + pProfile->m_NoSections = 0; + + if ( pFile == 0 ) + { + return sal_False; + } + + if ( pProfile == 0 ) + { + return sal_False; + } + + OSL_VERIFY(OslProfile_rewindFile(pFile, sal_False)); + + while ( ( pLine=OslProfile_getLine(pFile) ) != 0 ) + { + bWasAdded = addLine( pProfile, pLine ); + rtl_freeMemory( pLine ); + OSL_ASSERT(bWasAdded); + if ( ! bWasAdded ) + return (sal_False); + } + + for (i = 0; i < pProfile->m_NoLines; i++) + { + pStr = (sal_Char *)stripBlanks(pProfile->m_Lines[i], NULL); + + if ((*pStr == '\0') || (*pStr == ';')) + continue; + + if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == NULL) || + ((pChar - pStr) <= 2)) + { + /* insert entry */ + + if (pProfile->m_NoSections < 1) + continue; + + if ((pChar = strchr(pStr, '=')) == NULL) + pChar = pStr + strlen(pStr); + + if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1], + i, pStr, pChar - pStr)) + { + OSL_ASSERT(0); + continue; + } + + } + else + { + /* new section */ + + if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1)) + { + OSL_ASSERT(0); + continue; + } + + } + } + + return (sal_True); +} + +static sal_Bool storeProfile(osl_TProfileImpl* pProfile, sal_Bool bCleanup) +{ +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In storeProfile\n"); +#endif + + if (pProfile->m_Lines != NULL) + { + if (pProfile->m_Flags & FLG_MODIFIED) + { + sal_uInt32 i; + + osl_TFile* pTmpFile = osl_openTmpProfileImpl(pProfile); + + if ( pTmpFile == 0 ) + { + return sal_False; + } + + OSL_VERIFY(OslProfile_rewindFile(pTmpFile, sal_True)); + + for ( i = 0 ; i < pProfile->m_NoLines ; i++ ) + { + OSL_VERIFY(OslProfile_putLine(pTmpFile, pProfile->m_Lines[i])); + } + + if ( ! writeProfileImpl(pTmpFile) ) + { + if ( pTmpFile->m_pWriteBuf != 0 ) + { + free(pTmpFile->m_pWriteBuf); + } + + pTmpFile->m_pWriteBuf=0; + pTmpFile->m_nWriteBufLen=0; + pTmpFile->m_nWriteBufFree=0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out storeProfile [not flushed]\n"); +#endif + closeFileImpl(pTmpFile,pProfile->m_Flags); + + return sal_False; + } + + pProfile->m_Flags &= ~FLG_MODIFIED; + + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + closeFileImpl(pTmpFile,pProfile->m_Flags); + + osl_ProfileSwapProfileNames(pProfile); + + pProfile->m_pFile = openFileImpl(pProfile->m_FileName,pProfile->m_Flags); + + } + + if (bCleanup) + { + while (pProfile->m_NoLines > 0) + removeLine(pProfile, pProfile->m_NoLines - 1); + + free(pProfile->m_Lines); + pProfile->m_Lines = NULL; + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + + while (pProfile->m_NoSections > 0) + removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]); + + free(pProfile->m_Sections); + pProfile->m_Sections = NULL; + pProfile->m_NoSections = 0; + pProfile->m_MaxSections = 0; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out storeProfile [ok]\n"); +#endif + return (sal_True); +} + + +static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl* pProfile) +{ + osl_TFile* pFile=0; + sal_Char* pszExtension = "tmp"; + sal_Char pszTmpName[PATH_MAX]; + oslProfileOption PFlags=0; + + pszTmpName[0] = '\0'; + + /* generate tmp profilename */ + osl_ProfileGenerateExtension(pProfile->m_FileName,pszExtension,pszTmpName); + + if ( pszTmpName[0] == 0 ) + { + return 0; + } + + if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) ) + { + PFlags |= osl_Profile_WRITELOCK; + } + + /* open this file */ + pFile = openFileImpl(pszTmpName,pProfile->m_Flags | PFlags); + + + /* return new pFile */ + return pFile; +} + +static sal_Bool osl_ProfileSwapProfileNames(osl_TProfileImpl* pProfile) +{ + sal_Bool bRet = sal_False; + + sal_Char pszBakFile[PATH_MAX]; + sal_Char pszTmpFile[PATH_MAX]; + sal_Char pszIniFile[PATH_MAX]; + + pszBakFile[0] = '\0'; + pszTmpFile[0] = '\0'; + pszIniFile[0] = '\0'; + + osl_ProfileGenerateExtension(pProfile->m_FileName,"bak",pszBakFile); + + strcpy(pszIniFile,pProfile->m_FileName); + + osl_ProfileGenerateExtension(pProfile->m_FileName,"tmp",pszTmpFile); + + /* unlink bak */ + unlink( pszBakFile ); + + /* rename ini bak */ + rename( pszIniFile, pszBakFile ); + + /* rename tmp ini */ + rename( pszTmpFile, pszIniFile ); + + return bRet; +} + + +static void osl_ProfileGenerateExtension(sal_Char* pszFileName, sal_Char* pszExtension, sal_Char* pszTmpName) +{ + + strcpy(pszTmpName,pszFileName); + strcat(pszTmpName,"."); + strcat(pszTmpName,pszExtension); + + return; +} + + +static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile; + oslProfileOption PFlags=0; + sal_Bool bRet=sal_False; + + if ( bWriteable ) + { + PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK; + } + else + { + PFlags = osl_Profile_DEFAULT; + } + + + if (pProfile == NULL) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("AUTOOPEN MODE\n"); +#endif + + if ( ( pProfile = (osl_TProfileImpl*) osl_openProfile(0, PFlags ) ) != NULL ) + { + pProfile->m_Flags |= FLG_AUTOOPEN; + } + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("try to acquire\n"); +#endif + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ))) + { + osl_TStamp Stamp; + +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("Profile acquire DEFAULT MODE\n"); +#endif + if (! (pProfile->m_pFile = openFileImpl(pProfile->m_FileName, pProfile->m_Flags | PFlags ))) + return NULL; + + Stamp = OslProfile_getFileStamp(pProfile->m_pFile); + + if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp))) + { + pProfile->m_Stamp = Stamp; + + bRet=loadProfile(pProfile->m_pFile, pProfile); + OSL_ASSERT(bRet); + } + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("Profile acquire READ/WRITELOCK MODE\n"); +#endif + /* A readlock file could not be written */ + if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable) + { + return (NULL); + } + } + } + } + + return (pProfile); +} + +static sal_Bool releaseProfile(osl_TProfileImpl* pProfile) +{ + sal_Bool bRet=sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In releaseProfile\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [profile==0]\n"); +#endif + return sal_False; + } + + if (pProfile->m_Flags & FLG_AUTOOPEN) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [AUTOOPEN]\n"); +#endif + return (osl_closeProfile((oslProfile)pProfile)); + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("DEFAULT MODE\n"); +#endif + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ))) + { + if (pProfile->m_Flags & FLG_MODIFIED) + { + bRet=storeProfile(pProfile, sal_False); + OSL_ASSERT(bRet); + } + + + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + pProfile->m_pFile = NULL; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [ok]\n"); +#endif + return (sal_True); +} diff --git a/sal/osl/unx/salinit.cxx b/sal/osl/unx/salinit.cxx new file mode 100644 index 000000000000..7090a381235c --- /dev/null +++ b/sal/osl/unx/salinit.cxx @@ -0,0 +1,43 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sal.hxx" +#include "sal/config.h" + +#include "osl/process.h" +#include "sal/main.h" +#include "sal/types.h" + +extern "C" { + +void SAL_CALL sal_detail_initialize(int argc, char ** argv) { + osl_setCommandArgs(argc, argv); +} + +void SAL_CALL sal_detail_deinitialize() {} + +} diff --git a/sal/osl/unx/secimpl.h b/sal/osl/unx/secimpl.h new file mode 100644 index 000000000000..1d8f2aaa9419 --- /dev/null +++ b/sal/osl/unx/secimpl.h @@ -0,0 +1,47 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_SECURITYIMPL_H_ +#define _OSL_SECURITYIMPL_H_ + +#include <pwd.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _oslSecurityImpl { + struct passwd m_pPasswd; + char m_buffer[1]; /* should be a C99 flexible array member */ +} oslSecurityImpl; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/unx/security.c b/sal/osl/unx/security.c new file mode 100644 index 000000000000..d08326e65ebe --- /dev/null +++ b/sal/osl/unx/security.c @@ -0,0 +1,862 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <stddef.h> + +/* Solaris 8 has no C99 stdint.h, and Solaris generally seems not to miss it for + SIZE_MAX: */ +#if !defined __SUNPRO_C +#include <stdint.h> +#endif + +#include "system.h" + +#include <osl/security.h> +#include <osl/diagnose.h> + +#include "osl/thread.h" +#include "osl/file.h" + +#if defined LINUX || defined SOLARIS +#include <crypt.h> +#endif + +#include "secimpl.h" + +#ifndef NOPAM +#ifndef PAM_BINARY_MSG +#define PAM_BINARY_MSG 6 +#endif +#endif + +static oslSecurityError SAL_CALL +osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd, + oslSecurity* pSecurity); +sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax); +static sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax); +static sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax); +static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax); + +static sal_Bool sysconf_SC_GETPW_R_SIZE_MAX(size_t * value) { +#if defined _SC_GETPW_R_SIZE_MAX + long m; + errno = 0; + m = sysconf(_SC_GETPW_R_SIZE_MAX); + if (m == -1) { + /* _SC_GETPW_R_SIZE_MAX has no limit; some platforms like certain + FreeBSD versions support sysconf(_SC_GETPW_R_SIZE_MAX) in a broken + way and always set EINVAL, so be resilient here: */ + return sal_False; + } else { + OSL_ASSERT(m >= 0 && (unsigned long) m < SIZE_MAX); + *value = (size_t) m; + return sal_True; + } +#else + /* some platforms like Mac OS X 1.3 do not define _SC_GETPW_R_SIZE_MAX: */ + return sal_False; +#endif +} + +static oslSecurityImpl * growSecurityImpl( + oslSecurityImpl * impl, size_t * bufSize) +{ + size_t n = 0; + oslSecurityImpl * p = NULL; + if (impl == NULL) { + if (!sysconf_SC_GETPW_R_SIZE_MAX(&n)) { + /* choose something sensible (the callers of growSecurityImpl will + detect it if the allocated buffer is too small: */ + n = 1024; + } + } else if (*bufSize <= SIZE_MAX / 2) { + n = 2 * *bufSize; + } + if (n != 0) { + if (n <= SIZE_MAX - offsetof(oslSecurityImpl, m_buffer)) { + *bufSize = n; + n += offsetof(oslSecurityImpl, m_buffer); + } else { + *bufSize = SIZE_MAX - offsetof(oslSecurityImpl, m_buffer); + n = SIZE_MAX; + } + p = realloc(impl, n); + } + if (p == NULL) { + free(impl); + } + return p; +} + +static void deleteSecurityImpl(oslSecurityImpl * impl) { + free(impl); +} + +oslSecurity SAL_CALL osl_getCurrentSecurity() +{ + size_t n = 0; + oslSecurityImpl * p = NULL; + for (;;) { + struct passwd * found; + p = growSecurityImpl(p, &n); + if (p == NULL) { + return NULL; + } + switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) { + case ERANGE: + break; + case 0: + if (found != NULL) { + return p; + } + /* fall through */ + default: + deleteSecurityImpl(p); + return NULL; + } + } +} + + +#if defined LINUX && !defined NOPAM + +/* + * + * osl Routines for Pluggable Authentication Modules (PAM) + * tested with Linux-PAM 0.66 on Redhat-6.0 and + * Linux-PAM 0.64 on RedHat-5.2, + * XXX Will probably not run on PAM 0.59 or prior, since + * number of pam_response* responses has changed + * + */ + +#include <security/pam_appl.h> + +typedef struct { + char* name; + char* password; +} sal_PamData; + +typedef struct { + int (*pam_start)(const char *service_name, const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh); + int (*pam_end) (pam_handle_t *pamh, int pam_status); + int (*pam_authenticate) (pam_handle_t *pamh, int flags); + int (*pam_acct_mgmt) (pam_handle_t *pamh, int flags); +} sal_PamModule; + +/* + * Implement a pam-conversation callback-routine, + * it just supply name and password instead of prompting the user. + * I guess that echo-off means 'ask for password' and echo-on means + * 'ask for user-name'. In fact I've never been asked anything else + * than the password + * XXX Please notice that if a pam-module does ask anything else, we + * are completely lost, and a pam-module is free to do so + * XXX + */ + +static int +osl_PamConversation (int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + int i; + sal_Bool error; + sal_PamData *pam_data; + struct pam_response *p_reply; + + /* resource initialization */ + pam_data = (sal_PamData*) appdata_ptr; + p_reply = (struct pam_response *) calloc( num_msg, + sizeof(struct pam_response)); + if ( p_reply == NULL || pam_data == NULL ) + { + if ( p_reply != NULL ) + free ( p_reply ); + *response = NULL; + return PAM_CONV_ERR; + } + + /* pseudo dialog */ + error = sal_False; + for ( i = 0; i < num_msg ; i++ ) + { + switch ( msgm[ i ]->msg_style ) + { + case PAM_PROMPT_ECHO_OFF: + p_reply[ i ].resp_retcode = 0; + p_reply[ i ].resp = strdup( pam_data->password ); + break; + case PAM_PROMPT_ECHO_ON: + p_reply[ i ].resp_retcode = 0; + p_reply[ i ].resp = strdup( pam_data->name ); + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + case PAM_BINARY_PROMPT: + case PAM_BINARY_MSG: + p_reply[ i ].resp_retcode = 0; + p_reply[ i ].resp = NULL; + break; + default: + error = sal_True; + break; + } + } + + /* free resources on error */ + if ( error ) + { + for ( i = 0; i < num_msg ; i++ ) + if ( p_reply[ i ].resp ) + { + memset ( p_reply[ i ].resp, 0, + strlen( p_reply[ i ].resp ) ); + free ( p_reply[ i ].resp ); + } + free ( p_reply ); + + *response = NULL; + return PAM_CONV_ERR; + } + + /* well done */ + *response = p_reply; + return PAM_SUCCESS; +} + +#ifndef PAM_LINK +/* + * avoid linking against libpam.so, since it is not available on all systems, + * instead load-on-call, returns structure which holds pointer to + * pam-functions, + * library is never closed in case of success + */ + +static sal_PamModule* osl_getPAM() +{ + static sal_PamModule *pam_module = NULL; + static sal_Bool load_once = sal_False; + + if ( !load_once ) + { + /* get library-handle. cannot use osl-module, since + RTLD_GLOBAL is required for PAM-0.64 RH 5.2 + (but not for PAM-0.66 RH 6.0) */ + void *pam_hdl; + + pam_hdl = dlopen( "libpam.so.0", RTLD_GLOBAL | RTLD_LAZY ); + + if ( pam_hdl != NULL ) + pam_module = (sal_PamModule*)calloc( 1, sizeof(sal_PamModule) ); + + /* load functions */ + if ( pam_module != NULL ) + { + pam_module->pam_acct_mgmt = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_acct_mgmt" ); + pam_module->pam_authenticate + = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_authenticate" ); + pam_module->pam_end = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_end" ); + pam_module->pam_start = (int (*)(const char *, const char *, const struct pam_conv *, pam_handle_t **)) dlsym ( pam_hdl, "pam_start" ); + + /* free resources, if not completely successful */ + if ( (pam_module->pam_start == NULL) + || (pam_module->pam_end == NULL) + || (pam_module->pam_authenticate == NULL) + || (pam_module->pam_acct_mgmt == NULL) ) + { + free( pam_module ); + pam_module = NULL; + dlclose( pam_hdl ); + } + } + + /* never try again */ + load_once = sal_True; + } + + return pam_module; +} +#endif + +/* + * User Identification using PAM + */ + +static sal_Bool +osl_PamAuthentification( const sal_Char* name, const sal_Char* password ) +{ + sal_Bool success = sal_False; + +#ifndef PAM_LINK + sal_PamModule* pam_module; + + pam_module = osl_getPAM(); + if ( pam_module != NULL ) + { +#endif + pam_handle_t *pam_handle = NULL; + struct pam_conv pam_conversation; + sal_PamData pam_data; + + int return_value; + + pam_data.name = (char*) name; + pam_data.password = (char*) password; + + pam_conversation.conv = osl_PamConversation; + pam_conversation.appdata_ptr = (void*)(&pam_data); + +#ifndef PAM_LINK + return_value = pam_module->pam_start( "su", name, + &pam_conversation, &pam_handle); +#else + return_value = pam_start( "su", name, + &pam_conversation, &pam_handle); +#endif + if (return_value == PAM_SUCCESS ) +#ifndef PAM_LINK + return_value = pam_module->pam_authenticate(pam_handle, 0); +#else + return_value = pam_authenticate(pam_handle, 0); +#endif + if (return_value == PAM_SUCCESS ) +#ifndef PAM_LINK + return_value = pam_module->pam_acct_mgmt(pam_handle, 0); + pam_module->pam_end( pam_handle, return_value ); +#else + return_value = pam_acct_mgmt(pam_handle, 0); + pam_end( pam_handle, return_value ); +#endif + + success = (sal_Bool)(return_value == PAM_SUCCESS); +#ifndef PAM_LINK + } +#endif + + return success; +} + + +#ifndef CRYPT_LINK +/* dummy crypt, matches the interface of + crypt() but does not encrypt at all */ +static const sal_Char* SAL_CALL +osl_noCrypt ( const sal_Char *key, const sal_Char *salt ) +{ + (void) salt; /* unused */ + return key; +} + +/* load-on-call crypt library and crypt symbol */ +static void* SAL_CALL +osl_getCrypt() +{ + static char* (*crypt_sym)(const char*, const char*) = NULL; + static sal_Bool load_once = sal_False; + + if ( !load_once ) + { + void * crypt_library; + + crypt_library = dlopen( "libcrypt.so.1", RTLD_GLOBAL | RTLD_LAZY ); /* never closed */ + if ( crypt_library != NULL ) + crypt_sym = (char* (*)(const char *, const char *)) dlsym(crypt_library, "crypt" ); + if ( crypt_sym == NULL ) /* no libcrypt or libcrypt without crypt */ + crypt_sym = (char* (*)(const char *, const char *)) &osl_noCrypt; + + load_once = sal_True; + } + + return (void*)crypt_sym; +} + +/* replacement for crypt function for password encryption, uses either + strong encryption of dlopen'ed libcrypt.so.1 or dummy implementation + with no encryption. Objective target is to avoid linking against + libcrypt (not available on caldera open linux 2.2 #63822#) */ +static sal_Char* SAL_CALL +osl_dynamicCrypt ( const sal_Char *key, const sal_Char *salt ) +{ + char* (*dynamic_crypt)(char *, char *); + + dynamic_crypt = (char * (*)(char *, char *)) osl_getCrypt(); + + return dynamic_crypt( (sal_Char*)key, (sal_Char*)salt ); +} +#endif + +/* + * compare an encrypted and an unencrypted password for equality + * returns true if passwords are equal, false otherwise + * Note: uses crypt() and a mutex instead of crypt_r() since crypt_r needs + * more than 128KByte of external buffer for struct crypt_data + */ + +static sal_Bool SAL_CALL +osl_equalPasswords ( const sal_Char *pEncryptedPassword, const sal_Char *pPlainPassword ) +{ + static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER; + + sal_Bool success; + sal_Char salt[3]; + sal_Char *encrypted_plain; + + salt[0] = pEncryptedPassword[0]; + salt[1] = pEncryptedPassword[1]; + salt[2] = '\0'; + + pthread_mutex_lock(&crypt_mutex); + +#ifndef CRYPT_LINK + encrypted_plain = (sal_Char *)osl_dynamicCrypt( pPlainPassword, salt ); +#else + encrypted_plain = (sal_Char *)crypt( pPlainPassword, salt ); +#endif + success = (sal_Bool) (strcmp(pEncryptedPassword, encrypted_plain) == 0); + + pthread_mutex_unlock(&crypt_mutex); + + return success; +} + +#endif /* defined LINUX && !defined NOPAM */ +oslSecurityError SAL_CALL osl_loginUser( + rtl_uString *ustrUserName, + rtl_uString *ustrPassword, + oslSecurity *pSecurity + ) +{ + oslSecurityError Error; + rtl_String* strUserName=0; + rtl_String* strPassword=0; + sal_Char* pszUserName=0; + sal_Char* pszPassword=0; + + if ( ustrUserName != 0 ) + { + + rtl_uString2String( &strUserName, + rtl_uString_getStr(ustrUserName), + rtl_uString_getLength(ustrUserName), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszUserName = rtl_string_getStr(strUserName); + } + + + if ( ustrPassword != 0 ) + { + rtl_uString2String( &strPassword, + rtl_uString_getStr(ustrPassword), + rtl_uString_getLength(ustrPassword), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszPassword = rtl_string_getStr(strPassword); + } + + + Error=osl_psz_loginUser(pszUserName,pszPassword,pSecurity); + + if ( strUserName != 0 ) + { + rtl_string_release(strUserName); + } + + if ( strPassword) + { + rtl_string_release(strPassword); + } + + + return Error; +} + + +static oslSecurityError SAL_CALL +osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd, + oslSecurity* pSecurity) +{ +#if defined NETBSD || defined SCO || defined AIX || defined FREEBSD || \ + defined MACOSX + + return osl_Security_E_None; + +#else + + oslSecurityError nError = osl_Security_E_Unknown; + oslSecurityImpl * p = NULL; + if (pszUserName != NULL && pszPasswd != NULL && pSecurity != NULL) { + /* get nis or normal password, should succeed for any known user, but + perhaps the password is wrong (i.e. 'x') if shadow passwords are in + use or authentication must be done by PAM */ + size_t n = 0; + int err = 0; + struct passwd * found = NULL; + for (;;) { + p = growSecurityImpl(p, &n); + if (p == NULL) { + break; + } + err = getpwnam_r( + pszUserName, &p->m_pPasswd, p->m_buffer, n, &found); + if (err != ERANGE) { + break; + } + } + if (p != NULL && err == 0) { + if (found == NULL) { + nError = osl_Security_E_UserUnknown; + } else { +#if defined LINUX && !defined NOPAM + /* only root is able to read the /etc/shadow passwd, a normal + user even can't read his own encrypted passwd */ + if (osl_equalPasswords(p->m_pPasswd.pw_passwd, pszPasswd) || + osl_PamAuthentification(pszUserName, pszPasswd)) + { + nError = osl_Security_E_None; + } else { + char buffer[1024]; + struct spwd result_buf; + struct spwd * pShadowPasswd; + buffer[0] = '\0'; + if (getspnam_r( + pszUserName, &result_buf, buffer, sizeof buffer, + &pShadowPasswd) == 0 && + pShadowPasswd != NULL) + { + nError = + osl_equalPasswords( + pShadowPasswd->sp_pwdp, pszPasswd) + ? osl_Security_E_None + : osl_Security_E_WrongPassword; + } else if (getuid() == 0) { + /* mfe: Try to verify the root-password via nis */ + if (getspnam_r( + "root", &result_buf, buffer, sizeof buffer, + &pShadowPasswd) == 0 && + pShadowPasswd != NULL && + osl_equalPasswords( + pShadowPasswd->sp_pwdp, pszPasswd)) + { + nError = osl_Security_E_None; + } else { + /* mfe: we can't get via nis (glibc2.0.x has bug in + getspnam_r) we try it with the normal getspnam */ + static pthread_mutex_t pwmutex = + PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&pwmutex); + pShadowPasswd = getspnam("root"); + pthread_mutex_unlock(&pwmutex); + nError = + ((pShadowPasswd != NULL && + osl_equalPasswords( + pShadowPasswd->sp_pwdp, pszPasswd)) || + osl_PamAuthentification("root", pszPasswd)) + ? osl_Security_E_None + : osl_Security_E_WrongPassword; + } + } + } +#else + char buffer[1024]; + struct spwd spwdStruct; + buffer[0] = '\0'; +#ifndef NEW_SHADOW_API + if (getspnam_r(pszUserName, &spwdStruct, buffer, sizeof buffer) != NULL) +#else + if (getspnam_r(pszUserName, &spwdStruct, buffer, sizeof buffer, NULL) == 0) +#endif + { + char salt[3]; + char * cryptPasswd; + strncpy(salt, spwdStruct.sp_pwdp, 2); + salt[2] = '\0'; + cryptPasswd = (char *) crypt(pszPasswd, salt); + if (strcmp(spwdStruct.sp_pwdp, cryptPasswd) == 0) { + nError = osl_Security_E_None; + } else if (getuid() == 0 && +#ifndef NEW_SHADOW_API + (getspnam_r("root", &spwdStruct, buffer, sizeof buffer) != NULL)) +#else + (getspnam_r("root", &spwdStruct, buffer, sizeof buffer, NULL) == 0)) +#endif + { + /* if current process is running as root, allow to logon + as any other user */ + strncpy(salt, spwdStruct.sp_pwdp, 2); + salt[2] = '\0'; + cryptPasswd = (char *) crypt(pszPasswd, salt); + if (strcmp(spwdStruct.sp_pwdp, cryptPasswd) == 0) { + nError = osl_Security_E_None; + } + } else { + nError = osl_Security_E_WrongPassword; + } + } +#endif + } + } + } + if (nError == osl_Security_E_None) { + *pSecurity = p; + } else { + deleteSecurityImpl(p); + *pSecurity = NULL; + } + return nError; + +#endif +} + +oslSecurityError SAL_CALL osl_loginUserOnFileServer( + rtl_uString *strUserName, + rtl_uString *strPasswd, + rtl_uString *strFileServer, + oslSecurity *pSecurity + ) +{ + (void) strUserName; /* unused */ + (void) strPasswd; /* unused */ + (void) strFileServer; /* unused */ + (void) pSecurity; /* unused */ + return osl_Security_E_UserUnknown; +} + + +sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent) +{ + sal_Bool bRet=sal_False; + sal_Char pszIdent[1024]; + + pszIdent[0] = '\0'; + + bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent)); + + rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*ustrIdent != NULL); + + return bRet; +} + + +sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax) +{ + sal_Char buffer[32]; + sal_Int32 nChr; + + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid); + if ( nChr < 0 || SAL_INT_CAST(sal_uInt32, nChr) >= sizeof(buffer) + || SAL_INT_CAST(sal_uInt32, nChr) >= nMax ) + return sal_False; /* leave *pszIdent unmodified in case of failure */ + + memcpy(pszIdent, buffer, nChr+1); + return sal_True; +} + +sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName) +{ + sal_Bool bRet=sal_False; + sal_Char pszName[1024]; + + pszName[0] = '\0'; + + bRet = osl_psz_getUserName(Security,pszName,sizeof(pszName)); + + rtl_string2UString( ustrName, pszName, rtl_str_getLength( pszName ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*ustrName != NULL); + + return bRet; +} + + + +static sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + strncpy(pszName, pSecImpl->m_pPasswd.pw_name, nMax); + + return sal_True; +} + +sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory) +{ + sal_Bool bRet=sal_False; + sal_Char pszDirectory[PATH_MAX]; + + pszDirectory[0] = '\0'; + + bRet = osl_psz_getHomeDir(Security,pszDirectory,sizeof(pszDirectory)); + + if ( bRet == sal_True ) + { + rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pustrDirectory != NULL); + osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory ); + } + + return bRet; +} + + +static sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + /* if current user, check also environment for HOME */ + if (getuid() == pSecImpl->m_pPasswd.pw_uid) + { + sal_Char *pStr = NULL; +#ifdef SOLARIS + char buffer[8192]; + + struct passwd pwd; + struct passwd *ppwd; + +#ifdef _POSIX_PTHREAD_SEMANTICS + if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) ) + ppwd = NULL; +#else + ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) ); +#endif + + if ( ppwd ) + pStr = ppwd->pw_dir; +#else + pStr = getenv("HOME"); +#endif + + if ((pStr != NULL) && (strlen(pStr) > 0) && + (access(pStr, 0) == 0)) + strncpy(pszDirectory, pStr, nMax); + else + strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax); + } + else + strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax); + + return sal_True; +} + +sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory) +{ + sal_Bool bRet = sal_False; + sal_Char pszDirectory[PATH_MAX]; + + pszDirectory[0] = '\0'; + + bRet = osl_psz_getConfigDir(Security,pszDirectory,sizeof(pszDirectory)); + + if ( bRet == sal_True ) + { + rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pustrDirectory != NULL); + osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory ); + } + + return bRet; +} + +#ifndef MACOSX + +static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax) +{ + sal_Char *pStr = getenv("XDG_CONFIG_HOME"); + + if ((pStr == NULL) || (strlen(pStr) == 0) || + (access(pStr, 0) != 0)) + return (osl_psz_getHomeDir(Security, pszDirectory, nMax)); + + strncpy(pszDirectory, pStr, nMax); + return sal_True; +} + +#else + +/* + * FIXME: rewrite to use more flexible + * NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) + * as soon as we can bumb the baseline to Tiger (for NSApplicationSupportDirectory) and have + * support for Objective-C in the build environment + */ + +#define MACOSX_CONFIG_DIR "/Library/Application Support" +static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax) +{ + if( osl_psz_getHomeDir(Security, pszDirectory, nMax - sizeof(MACOSX_CONFIG_DIR) + 1) ) + { + strcat( pszDirectory, MACOSX_CONFIG_DIR ); + return sal_True; + } + + return sal_False; +} + +#endif + +sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + if (pSecImpl->m_pPasswd.pw_uid != 0) + return (sal_False); + + return (sal_True); +} + +void SAL_CALL osl_freeSecurityHandle(oslSecurity Security) +{ + deleteSecurityImpl(Security); +} + + +sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security) +{ + (void) Security; /* unused */ + return sal_False; +} + +void SAL_CALL osl_unloadUserProfile(oslSecurity Security) +{ + (void) Security; /* unused */ +} diff --git a/sal/osl/unx/semaphor.c b/sal/osl/unx/semaphor.c new file mode 100644 index 000000000000..c514b2dacff6 --- /dev/null +++ b/sal/osl/unx/semaphor.c @@ -0,0 +1,314 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/semaphor.h> +#include <osl/diagnose.h> + +#ifndef OSL_USE_SYS_V_SEMAPHORE + +/* This is the (default) POSIX thread-local semaphore variant */ + +/* + Implemetation notes: + The void* represented by oslSemaphore is used + as a pointer to an sem_t struct +*/ + +/*****************************************************************************/ +/* osl_createSemaphore */ +/*****************************************************************************/ + +oslSemaphore SAL_CALL osl_createSemaphore(sal_uInt32 initialCount) +{ + int ret = 0; + oslSemaphore Semaphore; + + Semaphore= malloc(sizeof(sem_t)); + + OSL_ASSERT(Semaphore); /* ptr valid? */ + + if ( Semaphore == 0 ) + { + return 0; + } + + /* unnamed semaphore, not shared between processes */ + + ret= sem_init((sem_t*)Semaphore, 0, initialCount); + + /* create failed? */ + if (ret != 0) + { + OSL_TRACE("osl_createSemaphore failed. Errno: %d; %s\n", + errno, + strerror(errno)); + + free(Semaphore); + Semaphore = NULL; + } + + return Semaphore; +} + +/*****************************************************************************/ +/* osl_destroySemaphore */ +/*****************************************************************************/ +void SAL_CALL osl_destroySemaphore(oslSemaphore Semaphore) +{ + if(Semaphore) /* ptr valid? */ + { + sem_destroy((sem_t*)Semaphore); + free(Semaphore); + } +} + +/*****************************************************************************/ +/* osl_acquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireSemaphore(oslSemaphore Semaphore) { + + OSL_ASSERT(Semaphore != 0); /* abort in debug mode */ + + if (Semaphore != 0) /* be tolerant in release mode */ + { + return (sem_wait((sem_t*)Semaphore) == 0); + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_tryToAcquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireSemaphore(oslSemaphore Semaphore) { + + OSL_ASSERT(Semaphore != 0); /* abort in debug mode */ + if (Semaphore != 0) /* be tolerant in release mode */ + { + return (sem_trywait((sem_t*)Semaphore) == 0); + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_releaseSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseSemaphore(oslSemaphore Semaphore) { + + OSL_ASSERT(Semaphore != 0); /* abort in debug mode */ + + if (Semaphore != 0) /* be tolerant in release mode */ + { + return (sem_post((sem_t*)Semaphore) == 0); + } + + return sal_False; +} + +#else /* OSL_USE_SYS_V_SEMAPHORE */ + +/*******************************************************************************/ + +/* This is the SYS V private semaphore variant */ + +/* + Implemetation notes: + The void* represented by oslSemaphore is used + as a pointer to an osl_TSemImpl struct +*/ + + +#if defined(NETBSD) +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ + u_short *array; /* array for GETALL & SETALL */ +}; +#endif + +typedef struct _osl_TSemImpl +{ + int m_Id; + +} osl_TSemImpl; + +/*****************************************************************************/ +/* osl_createSemaphore */ +/*****************************************************************************/ +oslSemaphore SAL_CALL osl_createSemaphore(sal_uInt32 initialCount) +{ + union semun arg; + + oslSemaphore Semaphore; + osl_TSemImpl* pSem; + + Semaphore= malloc(sizeof(osl_TSemImpl)); + OSL_POSTCOND(Semaphore, "malloc failed\n"); /* ptr valid? */ + + pSem= (osl_TSemImpl*)Semaphore; + + + /* unnamed (private) semaphore */ + + pSem->m_Id= semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT); + + + /* create failed? */ + if (pSem->m_Id < 0) + { + OSL_TRACE("osl_createSemaphore failed (semget). Errno: %d; %s\n", + errno, + strerror(errno)); + + free(Semaphore); + return 0; + } + + /* set initial count */ + + arg.val= initialCount; + + if(semctl(pSem->m_Id, 0, SETVAL, arg) < 0) + { + OSL_TRACE("osl_createSemaphore failed (semctl(SETVAL)). Errno: %d; %s\n", + errno, + strerror(errno)); + + if(semctl(pSem->m_Id, 0, IPC_RMID, arg) < 0) + { + OSL_TRACE("semctl(IPC_RMID) failed. Errno: %d; %s\n", errno, strerror(errno)); + } + + free(Semaphore); + return 0; + } + + + return Semaphore; +} + +/*****************************************************************************/ +/* osl_destroySemaphore */ +/*****************************************************************************/ +void SAL_CALL osl_destroySemaphore(oslSemaphore Semaphore) { + + if(Semaphore) /* ptr valid? */ + { + union semun arg; + + osl_TSemImpl* pSem= (osl_TSemImpl*)Semaphore; + + if(semctl(pSem->m_Id, 0, IPC_RMID, arg) < 0) + + { + OSL_TRACE("osl_destroySemaphore failed. (semctl(IPC_RMID)). Errno: %d; %s\n", + errno, + strerror(errno)); + } + + free(Semaphore); + } +} + +/*****************************************************************************/ +/* osl_acquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireSemaphore(oslSemaphore Semaphore) { + + /* abort in debug mode */ + OSL_PRECOND(Semaphore != 0, "Semaphore not created\n"); + + + if (Semaphore != 0) /* be tolerant in release mode */ + { + struct sembuf op; + osl_TSemImpl* pSem= (osl_TSemImpl*)Semaphore; + + op.sem_num= 0; + op.sem_op= -1; + op.sem_flg= SEM_UNDO; + + return semop(pSem->m_Id, &op, 1) >= 0; + + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_tryToAcquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireSemaphore(oslSemaphore Semaphore) { + + /* abort in debug mode */ + OSL_PRECOND(Semaphore != 0, "Semaphore not created\n"); + + if (Semaphore != 0) /* be tolerant in release mode */ + { + struct sembuf op; + osl_TSemImpl* pSem= (osl_TSemImpl*)Semaphore; + + op.sem_num= 0; + op.sem_op= -1; + op.sem_flg= SEM_UNDO | IPC_NOWAIT; + + return semop(pSem->m_Id, &op, 1) >= 0; + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_releaseSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseSemaphore(oslSemaphore Semaphore) +{ + + /* abort in debug mode */ + OSL_PRECOND(Semaphore != 0, "Semaphore not created\n"); + + if (Semaphore != 0) /* be tolerant in release mode */ + { + struct sembuf op; + osl_TSemImpl* pSem= (osl_TSemImpl*)Semaphore; + + op.sem_num= 0; + op.sem_op= 1; + op.sem_flg= SEM_UNDO; + + return semop(pSem->m_Id, &op, 1) >= 0; + } + + return sal_False; +} + +#endif /* OSL_USE_SYS_V_SEMAPHORE */ + diff --git a/sal/osl/unx/signal.c b/sal/osl/unx/signal.c new file mode 100644 index 000000000000..5563375d9567 --- /dev/null +++ b/sal/osl/unx/signal.c @@ -0,0 +1,1093 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/* system headers */ +#include "system.h" + +#define MAX_STACK_FRAMES 256 + +#if defined( MACOSX ) + +#if defined( INTEL ) +#include "backtrace.h" +#define INCLUDE_BACKTRACE +#define STACKTYPE "MacOsX_X86" +#endif /* INTEL */ + +#endif /* MACOSX */ + +#ifdef LINUX +#include <execinfo.h> +#include <link.h> +#define INCLUDE_BACKTRACE +#define STACKTYPE "Linux" +#endif + +#ifdef SOLARIS + +#include "backtrace.h" +#define INCLUDE_BACKTRACE + +#if defined( SPARC ) +#define STACKTYPE "Solaris_Sparc" +#elif defined( INTEL ) +#define STACKTYPE "Solaris_X86" +#else +#define STACKTYPE "Solaris_Unknown" +#endif + +#endif /* defined SOLARIS */ + +#include <osl/diagnose.h> +#include <osl/mutex.h> +#include <osl/signal.h> +#include <osl/process.h> +#include <osl/thread.h> +#include <rtl/bootstrap.h> +#include <rtl/digest.h> + +#include "file_path_helper.h" + +#define ACT_IGNORE 1 +#define ACT_EXIT 2 +#define ACT_SYSTEM 3 +#define ACT_HIDE 4 +#ifdef SAL_ENABLE_CRASH_REPORT +# define ACT_ABORT 5 +#else +# define ACT_ABORT ACT_SYSTEM +#endif + +#define MAX_PATH_LEN 2048 + +typedef struct _oslSignalHandlerImpl +{ + oslSignalHandlerFunction Handler; + void* pData; + struct _oslSignalHandlerImpl* pNext; +} oslSignalHandlerImpl; + +static struct SignalAction +{ + int Signal; + int Action; + void (*Handler)(int); +} Signals[] = +{ + { SIGHUP, ACT_IGNORE, NULL }, /* hangup */ + { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */ + { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */ + { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */ +/* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/ + { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */ +#if ( SIGIOT != SIGABRT ) + { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */ +#endif + { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */ +#ifdef SIGEMT + { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */ +/* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/ +/* SIGEMT may also be used by the profiler - so it is probably not a good +plan to have the new handler use this signal*/ +#endif + { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */ + { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */ + { SIGBUS, ACT_ABORT, NULL }, /* bus error */ + { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */ +#ifdef SIGSYS + { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */ +#endif + { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */ + { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */ + { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */ + { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */ + { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */ + { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */ +#ifdef SIGPWR + { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */ +#endif + { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */ + { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */ +#ifdef SIGPOLL + { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occured */ +#endif + { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */ + { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */ + { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */ + { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */ + { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */ + { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */ + { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */ +/*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do +not get taken by the new handler - the new handler does not pass on context +information which causes 'collect' to crash. This is a way of avoiding +what looks like a bug in the new handler*/ + { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */ + { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */ +}; +const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction); + +static sal_Bool bErrorReportingEnabled = sal_True; +static sal_Bool bInitSignal = sal_False; +static oslMutex SignalListMutex; +static oslSignalHandlerImpl* SignalList; +static sal_Bool bDoHardKill = sal_False; +static sal_Bool bSetSEGVHandler = sal_False; +static sal_Bool bSetWINCHHandler = sal_False; +static sal_Bool bSetILLHandler = sal_False; + +static void SignalHandlerFunction(int); + +static void getExecutableName_Impl (rtl_String ** ppstrProgName) +{ + rtl_uString * ustrProgFile = 0; + osl_getExecutableFile (&ustrProgFile); + if (ustrProgFile) + { + rtl_uString * ustrProgName = 0; + osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName); + if (ustrProgName != 0) + { + rtl_uString2String ( + ppstrProgName, + rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS); + rtl_uString_release (ustrProgName); + } + rtl_uString_release (ustrProgFile); + } +} + +static sal_Bool is_soffice_Impl (void) +{ + sal_Int32 idx = -1; + rtl_String * strProgName = 0; + + getExecutableName_Impl (&strProgName); + if (strProgName) + { + idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice"); + rtl_string_release (strProgName); + } + return (idx != -1); +} + +static sal_Bool InitSignal() +{ + int i; + struct sigaction act; + struct sigaction oact; + sigset_t unset; + + if (is_soffice_Impl()) + { + sal_uInt32 argi; + sal_uInt32 argc; + rtl_uString *ustrCommandArg = 0; + + argc = osl_getCommandArgCount(); + for ( argi = 0; argi < argc; argi++ ) + { + if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg)) + { + if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean")) + { + bDoHardKill = sal_True; + break; + } + } + } + if (ustrCommandArg) + { + rtl_uString_release (ustrCommandArg); + ustrCommandArg = 0; + } + + // WORKAROUND FOR SEGV HANDLER CONFLICT + // + // the java jit needs SIGSEGV for proper work + // and we need SIGSEGV for the office crashguard + // + // TEMPORARY SOLUTION: + // the office sets the signal handler during startup + // java can than overwrite it, if needed + bSetSEGVHandler = sal_True; + + // WORKAROUND FOR WINCH HANDLER (SEE ABOVE) + bSetWINCHHandler = sal_True; + + // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE) + bSetILLHandler = sal_True; + } + + SignalListMutex = osl_createMutex(); + + act.sa_handler = SignalHandlerFunction; + act.sa_flags = SA_RESTART; + + sigfillset(&(act.sa_mask)); + + /* Initialize the rest of the signals */ + for (i = 0; i < NoSignals; i++) + { + /* hack: stomcatd is attaching JavaVM wich dont work with an sigaction(SEGV) */ + if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV) + && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH) + && (bSetILLHandler || Signals[i].Signal != SIGILL)) + { + if (Signals[i].Action != ACT_SYSTEM) + { + if (Signals[i].Action == ACT_HIDE) + { + struct sigaction ign; + + ign.sa_handler = SIG_IGN; + ign.sa_flags = 0; + sigemptyset(&ign.sa_mask); + + if (sigaction(Signals[i].Signal, &ign, &oact) == 0) + Signals[i].Handler = oact.sa_handler; + else + Signals[i].Handler = SIG_DFL; + } + else + if (sigaction(Signals[i].Signal, &act, &oact) == 0) + Signals[i].Handler = oact.sa_handler; + else + Signals[i].Handler = SIG_DFL; + } + } + } + + /* Clear signal mask inherited from parent process (on Mac OS X, upon a + crash soffice re-execs itself from within the signal handler, so the + second soffice would have the guilty signal blocked and would freeze upon + encountering a similar crash again): */ + if (sigemptyset(&unset) < 0 || + pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0) + { + OSL_TRACE("sigemptyset or pthread_sigmask failed"); + } + + return sal_True; +} + +static sal_Bool DeInitSignal() +{ + int i; + struct sigaction act; + + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + + /* Initialize the rest of the signals */ + for (i = NoSignals - 1; i >= 0; i--) + if (Signals[i].Action != ACT_SYSTEM) + { + act.sa_handler = Signals[i].Handler; + + sigaction(Signals[i].Signal, &act, NULL); + } + + osl_destroyMutex(SignalListMutex); + + return sal_False; +} + +#if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE) + +/*****************************************************************************/ +/* Generate MD5 checksum */ +/*****************************************************************************/ + +static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen ) +{ + sal_uInt32 nBytesProcessed = 0; + + FILE *fp = fopen( filename, "r" ); + + if ( fp ) + { + rtlDigest digest = rtl_digest_createMD5(); + + if ( digest ) + { + size_t nBytesRead; + sal_uInt8 buffer[4096]; + rtlDigestError error = rtl_Digest_E_None; + + while ( rtl_Digest_E_None == error && + 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) ) + { + error = rtl_digest_updateMD5( digest, buffer, nBytesRead ); + nBytesProcessed += nBytesRead; + } + + if ( rtl_Digest_E_None == error ) + { + error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen ); + } + + if ( rtl_Digest_E_None != error ) + nBytesProcessed = 0; + + rtl_digest_destroyMD5( digest ); + } + + fclose( fp ); + } + + return nBytesProcessed; +} + +/*****************************************************************************/ +/* Call crash reporter */ +/*****************************************************************************/ + +/* Helper function to encode and write a string to a stream */ + +static int fputs_xml( const char *string, FILE *stream ) +{ + int result = 0; + + while ( result >= 0 && *string ) + { + switch( *string ) + { + case '&': + result = fputs( "&", stream ); + break; + case '<': + result = fputs( "<", stream ); + break; + case '>': + result = fputs( ">", stream ); + break; + default: + result = fputc( *string, stream ); + break; + } + + string++; + } + + return result; +} +#endif + +/* Create intermediate files and run crash reporter */ + +#define REPORTENV_PARAM "-crashreportenv:" + +#if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \ + defined LINUX + +typedef struct +{ + const char *name; + ElfW(Off) offset; +} dynamic_entry; + +static int +callback(struct dl_phdr_info *info, size_t size, void *data) +{ + const ElfW(Phdr) *pDynamic = NULL; + + if (size == sizeof(struct dl_phdr_info)) + { + int i; + for (i = 0; i < info->dlpi_phnum; ++i) + { + if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) + { + pDynamic = &(info->dlpi_phdr[i]); + break; + } + } + } + + if (pDynamic) + { + char buffer[100]; + int len; + char exe[PATH_MAX]; + const char *dsoname = info->dlpi_name; + + dynamic_entry* entry = (dynamic_entry*)data; + + if (strcmp(dsoname, "") == 0) + { + snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid()); + if ((len = readlink(buffer, exe, PATH_MAX)) != -1) + { + exe[len] = '\0'; + dsoname = exe; + } + } + + if (strcmp(dsoname, entry->name) == 0) + { + entry->offset = pDynamic->p_offset; + return 1; + } + } + return 0; +} + +/* Get the location of the .dynamic section offset for the given elf file. + * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo + * + * We want to know this value so that if the binaries have been modifed + * by prelink then we can still process the call stack on server side + * by comparing this value to that of an "un-prelinked but known to be + * otherwise equivalent" version of those binaries and adjust the call + * stack addresses by the differences between .dynamic addresses so as + * to be able to map the prelinked addresses back to the unprelinked + * addresses + * + * cmc@openoffice.org + */ +static ElfW(Off) +dynamic_section_offset(const char *name) +{ + dynamic_entry entry; + + entry.name = name; + entry.offset = 0; + + dl_iterate_phdr(callback, &entry); + + return entry.offset; +} +#endif + +static int ReportCrash( int Signal ) +{ +#ifdef SAL_ENABLE_CRASH_REPORT + static sal_Bool bCrashReporterExecuted = sal_False; + sal_Bool bAutoCrashReport = sal_False; + + sal_uInt32 argi; + sal_uInt32 argc; + rtl_uString *ustrCommandArg = NULL; + + if ( !bErrorReportingEnabled ) + return -1; + + argc = osl_getCommandArgCount(); + + for ( argi = 0; argi < argc; argi++ ) + { + if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) ) + { + if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-nocrashreport" ) ) + { + rtl_uString_release( ustrCommandArg ); + return -1; + } + else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-autocrashreport" ) ) + { + bAutoCrashReport = sal_True; + } + else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( + rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ), + REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) + ) + { + rtl_uString *ustrEnvironment = NULL; + rtl_String *strEnv = NULL; + + rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) ); + + if ( ustrEnvironment ) + { + rtl_uString2String( + &strEnv, + rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ), + osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS + ); + + if ( strEnv ) + { + putenv( rtl_string_getStr( strEnv ) ); + rtl_string_release( strEnv ); + } + + rtl_uString_release( ustrEnvironment ); + } + + } + + } + } + + if ( ustrCommandArg ) + rtl_uString_release( ustrCommandArg ); + + if ( !bCrashReporterExecuted ) + { + int i; + /* struct sigaction act; */ + + for (i = 0; i < NoSignals; i++) + { + if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT ) + { + int ret; + char szShellCmd[512] = { '\0' }; + char *pXMLTempName = NULL; + char *pStackTempName = NULL; + char *pChecksumTempName = NULL; + +#ifdef INCLUDE_BACKTRACE + char szXMLTempNameBuffer[L_tmpnam]; + char szChecksumTempNameBuffer[L_tmpnam]; + char szStackTempNameBuffer[L_tmpnam]; + + void *stackframes[MAX_STACK_FRAMES]; + int iFrame; + int nFrames = backtrace( stackframes, sizeof(stackframes)/sizeof(stackframes[0])); + + FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL; + int fdxml, fdstk, fdchksum; + + strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) ); + strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) ); + + strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) ); + strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) ); + + strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) ); + strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) ); + + fdxml = mkstemp(szXMLTempNameBuffer); + fdstk = mkstemp(szStackTempNameBuffer); + fdchksum = mkstemp(szChecksumTempNameBuffer); + + xmlout = fdopen( fdxml , "w" ); + stackout = fdopen( fdstk , "w" ); + checksumout = fdopen( fdchksum, "w" ); + + pXMLTempName = szXMLTempNameBuffer; + pStackTempName = szStackTempNameBuffer; + pChecksumTempName = szChecksumTempNameBuffer; + + + if ( xmlout && stackout && checksumout ) + { + fprintf( xmlout, "<errormail:Stack type=\"%s\">\n", STACKTYPE ); + + fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\n" ); + + for ( iFrame = 0; iFrame < nFrames; iFrame++ ) + { + Dl_info dl_info; + + fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":", + SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) ); + + fprintf( xmlout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"", + iFrame, + SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) + ); + + memset( &dl_info, 0, sizeof(dl_info) ); + + /* dladdr may fail */ + if ( dladdr( stackframes[iFrame], &dl_info) ) + { + const char *dli_fname = NULL; + char *dli_fdir = NULL; + char szDirectory[PATH_MAX]; + char szCanonicDirectory[PATH_MAX]; + + /* Don't expect that dladdr filled all members of dl_info */ + + dli_fname = dl_info.dli_fname ? strrchr( dl_info.dli_fname, '/' ) : NULL; + if ( dli_fname ) + { + ++dli_fname; + memcpy( szDirectory, dl_info.dli_fname, dli_fname - dl_info.dli_fname ); + szDirectory[dli_fname - dl_info.dli_fname] = 0; + + dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory; + + if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' ) + strcat( dli_fdir, "/" ); + } + else + dli_fname = dl_info.dli_fname; + + /* create checksum of library on stack */ + if ( dli_fname ) + { + sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5]; + + sal_uInt32 nBytesProcessed = calc_md5_checksum( + dl_info.dli_fname, checksum, sizeof(checksum) ); + if ( nBytesProcessed ) + { + int j; + + fprintf( checksumout, "<errormail:Checksum sum=\"0x" ); + for ( j = 0; j < 16; fprintf( checksumout, "%02X", checksum[j++] ) ); + fprintf( checksumout, + "\" bytes=\"%lu\" file=\"%s\"/>\n", + SAL_INT_CAST( + unsigned long, nBytesProcessed), + dli_fname ); + } + } + + if ( dl_info.dli_fbase && dl_info.dli_fname ) + { +#ifdef LINUX + ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname); + fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset); +#endif + + fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x", + dl_info.dli_fname, + (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase + ); + + fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase ); + if ( dli_fname ) + fprintf( xmlout, " name=\"%s\"", dli_fname ); + + if ( dli_fdir ) + fprintf( xmlout, " path=\"%s\"", dli_fdir ); + +#ifdef LINUX + fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset ); +#endif + } + else + fprintf( stackout, " ????????" ); + + if ( dl_info.dli_sname && dl_info.dli_saddr ) + { + fputs( " (", stackout ); + fputs_xml( dl_info.dli_sname, stackout ); + fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)", + (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr ); + + fputs( " ordinal=\"", xmlout ); + fputs_xml( dl_info.dli_sname, xmlout ); + fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"", + (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr ); + } + + } + else /* dladdr failed */ + { + fprintf( stackout, " ????????" ); + } + + fprintf( stackout, "\n" ); + fprintf( xmlout, "/>\n" ); + + } + + fprintf( xmlout, "</errormail:Stack>\n" ); + fprintf( checksumout, "</errormail:Checksums>\n" ); + } + else + { + pXMLTempName = NULL; + pStackTempName = NULL; + pChecksumTempName = NULL; + } + + if ( stackout ) + fclose( stackout ); + if ( xmlout ) + fclose( xmlout ); + if ( checksumout ) + fclose( checksumout ); + + if ( pXMLTempName && pChecksumTempName && pStackTempName ) +#endif /* INCLUDE_BACKTRACE */ + { + rtl_uString * crashrep_url = NULL; + rtl_uString * crashrep_path = NULL; + rtl_String * crashrep_path_system = NULL; + rtl_string2UString( + &crashrep_url, + RTL_CONSTASCII_USTRINGPARAM( + "$BRAND_BASE_DIR/program/crashrep"), + OSTRING_TO_OUSTRING_CVTFLAGS); + rtl_bootstrap_expandMacros(&crashrep_url); + osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path); + rtl_uString2String( + &crashrep_path_system, + rtl_uString_getStr(crashrep_path), + rtl_uString_getLength(crashrep_path), + osl_getThreadTextEncoding(), + (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR + | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)); + rtl_uString_release(crashrep_url); + rtl_uString_release(crashrep_path); +#if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX) + snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]), + "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), + Signal, + pXMLTempName, + pChecksumTempName, + pStackTempName, + bAutoCrashReport ? " -send" : "" ); +#elif defined INCLUDE_BACKTRACE && defined SOLARIS + snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]), + "%s -p %d -s %d -xml %s -chksum %s -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), + Signal, + pXMLTempName, + pChecksumTempName, + bAutoCrashReport ? " -send" : "" ); +#else + snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]), + "%s -p %d -s %d -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), Signal, bAutoCrashReport ? " -send" : "" ); +#endif + rtl_string_release(crashrep_path_system); + } + + ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd ); + + if ( pXMLTempName ) + unlink( pXMLTempName ); + + if ( pStackTempName ) + unlink( pStackTempName ); + + if ( pChecksumTempName ) + unlink( pChecksumTempName ); + + if ( -1 != ret ) + { + bCrashReporterExecuted = sal_True; + return 1; + } + else + return -1; + + } + } + + return 0; + } + + return 1; +#else /* defined SAL_ENABLE_CRASH_REPORT */ + /* the utility crash_report is not build, so do the same as when + the option -nocrashreport is used */ + (void) Signal; // avoid warnings + return -1; +#endif /* defined SAL_ENABLE_CRASH_REPORT */ +} + +static void PrintStack( int sig ) +{ +#if ! defined(MACOSX) || defined(INCLUDE_BACKTRACE) + void *buffer[MAX_STACK_FRAMES]; + int size = backtrace( buffer, sizeof(buffer) / sizeof(buffer[0]) ); +#endif + + fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig ); + +#if defined(MACOSX) && ! defined(INCLUDE_BACKTRACE) + fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" ); +#else + if ( size > 0 ) + { + fputs( "Stack:\n", stderr ); + backtrace_symbols_fd( buffer, size, fileno(stderr) ); + } +#endif +} + +static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) +{ + oslSignalHandlerImpl* pHandler = SignalList; + oslSignalAction Action = osl_Signal_ActCallNextHdl; + + while (pHandler != NULL) + { + if ((Action = pHandler->Handler(pHandler->pData, pInfo)) + != osl_Signal_ActCallNextHdl) + break; + + pHandler = pHandler->pNext; + } + + return Action; +} + +void CallSystemHandler(int Signal) +{ + int i; + struct sigaction act; + + for (i = 0; i < NoSignals; i++) + { + if (Signals[i].Signal == Signal) + break; + } + + if (i < NoSignals) + { + if ((Signals[i].Handler == NULL) || + (Signals[i].Handler == SIG_DFL) || + (Signals[i].Handler == SIG_IGN) || + (Signals[i].Handler == SIG_ERR)) + { + switch (Signals[i].Action) + { + case ACT_EXIT: /* terminate */ + /* prevent dumping core on exit() */ + _exit(255); + break; + + case ACT_ABORT: /* terminate witch core dump */ + ReportCrash( Signal ); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + sigaction(SIGABRT, &act, NULL); + PrintStack( Signal ); + abort(); + break; + + case ACT_IGNORE: /* ignore */ + break; + + default: /* should never happen */ + OSL_ASSERT(0); + } + } + else + (*Signals[i].Handler)(Signal); + } +} + + +/*****************************************************************************/ +/* SignalHandlerFunction */ +/*****************************************************************************/ +void SignalHandlerFunction(int Signal) +{ + oslSignalInfo Info; + struct sigaction act; + + Info.UserSignal = Signal; + Info.UserData = NULL; + + switch (Signal) + { + case SIGBUS: + case SIGILL: + case SIGSEGV: + case SIGIOT: +#if ( SIGIOT != SIGABRT ) + case SIGABRT: +#endif + Info.Signal = osl_Signal_AccessViolation; + break; + + case -1: + Info.Signal = osl_Signal_IntegerDivideByZero; + break; + + case SIGFPE: + Info.Signal = osl_Signal_FloatDivideByZero; + break; + + case SIGINT: + case SIGTERM: + case SIGQUIT: + case SIGHUP: + Info.Signal = osl_Signal_Terminate; + break; + + default: + Info.Signal = osl_Signal_System; + break; + } + + ReportCrash( Signal ); + + /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation)) + _exit(255); + /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + + + switch (CallSignalHandler(&Info)) + { + case osl_Signal_ActCallNextHdl: + CallSystemHandler(Signal); + break; + + case osl_Signal_ActAbortApp: + ReportCrash( Signal ); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + sigaction(SIGABRT, &act, NULL); + PrintStack( Signal ); + abort(); + break; + + case osl_Signal_ActKillApp: + /* prevent dumping core on exit() */ + _exit(255); + break; + default: + break; + } +} + +/*****************************************************************************/ +/* osl_addSignalHandler */ +/*****************************************************************************/ +oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) +{ + oslSignalHandlerImpl* pHandler; + + OSL_ASSERT(Handler != NULL); + if ( Handler == 0 ) + { + return 0; + } + + if (! bInitSignal) + bInitSignal = InitSignal(); + + pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl)); + + if (pHandler != NULL) + { + pHandler->Handler = Handler; + pHandler->pData = pData; + + osl_acquireMutex(SignalListMutex); + + pHandler->pNext = SignalList; + SignalList = pHandler; + + osl_releaseMutex(SignalListMutex); + + return (pHandler); + } + + return (NULL); +} + +/*****************************************************************************/ +/* osl_removeSignalHandler */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) +{ + oslSignalHandlerImpl *pHandler, *pPrevious = NULL; + + OSL_ASSERT(Handler != NULL); + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + pHandler = SignalList; + + while (pHandler != NULL) + { + if (pHandler == Handler) + { + if (pPrevious) + pPrevious->pNext = pHandler->pNext; + else + SignalList = pHandler->pNext; + + osl_releaseMutex(SignalListMutex); + + if (SignalList == NULL) + bInitSignal = DeInitSignal(); + + free(pHandler); + + return (sal_True); + } + + pPrevious = pHandler; + pHandler = pHandler->pNext; + } + + osl_releaseMutex(SignalListMutex); + + return (sal_False); +} + +/*****************************************************************************/ +/* osl_raiseSignal */ +/*****************************************************************************/ +oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) +{ + oslSignalInfo Info; + oslSignalAction Action; + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + Info.Signal = osl_Signal_User; + Info.UserSignal = UserSignal; + Info.UserData = UserData; + + Action = CallSignalHandler(&Info); + + osl_releaseMutex(SignalListMutex); + + return (Action); +} + +/*****************************************************************************/ +/* osl_setErrorReporting */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) +{ + sal_Bool bOld = bErrorReportingEnabled; + bErrorReportingEnabled = bEnable; + + return bOld; +} diff --git a/sal/osl/unx/socket.c b/sal/osl/unx/socket.c new file mode 100644 index 000000000000..c8faf6c028f5 --- /dev/null +++ b/sal/osl/unx/socket.c @@ -0,0 +1,3062 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/socket.h> +#include <osl/diagnose.h> +#include <osl/mutex.h> +#include <osl/signal.h> + +#include <rtl/alloc.h> + +#include <ctype.h> +#include <sal/types.h> + +#include "sockimpl.h" + + +/* defines for poll */ +#ifdef HAVE_POLL_H +#undef HAVE_POLL_H +#endif + +#if defined(LINUX) || defined(NETBSD) || defined ( FREEBSD ) || defined (MACOSX) +#include <sys/poll.h> +#define HAVE_POLL_H +#endif /* HAVE_POLL_H */ + +#if defined(SOLARIS) +#include <poll.h> +#define HAVE_POLL_H +#endif /* SOLARIS */ + +#ifndef HAVE_POLL_H +#define POLLIN 0x0001 +#define POLLOUT 0x0002 +#define POLLPRI 0x0004 +#endif /* HAVE_POLL_H */ + + +/* defines for shutdown */ +#define SD_RECEIVE 0 +#define SD_SEND 1 +#define SD_BOTH 2 + + +/* + oslSocketAddr is a pointer to a Berkeley struct sockaddr. + I refrained from using sockaddr_in because of possible further + extensions of this socket-interface (IP-NG?). + The intention was to hide all Berkeley data-structures from + direct access past the osl-interface. + + The current implementation is internet (IP) centered. All + the constructor-functions (osl_create...) take parameters + that will probably make sense only in the IP-environment + (e.g. because of using the dotted-address-format). + + If the interface will be extended to host other protocol- + families, I expect no externally visible changes in the + existing functions. You'll probably need only new + constructor-functions who take the different address + formats into consideration (maybe a long dotted address + or whatever). +*/ + +/* _Note_ that I rely on the fact that oslSocketAddr and struct sockaddr */ +/* are the same! I don't like it very much but see no other easy way to */ +/* conceal the struct sockaddr from the eyes of the user. */ + + +#define OSL_INVALID_SOCKET -1 +#define OSL_SOCKET_ERROR -1 + + +/* Buffer size for gethostbyname */ +#define MAX_HOSTBUFFER_SIZE 2048 + +/*****************************************************************************/ +/* enum oslAddrFamily */ +/*****************************************************************************/ + +/* map */ +static unsigned long FamilyMap[]= { + AF_INET, /* osl_Socket_FamilyInet */ + AF_IPX, /* osl_Socket_FamilyIpx */ + 0 /* osl_Socket_FamilyInvalid */ +}; + +/* reverse map */ +static oslAddrFamily osl_AddrFamilyFromNative(sal_uInt32 nativeType) +{ + oslAddrFamily i= (oslAddrFamily)0; + + while(i != osl_Socket_FamilyInvalid) + { + if(FamilyMap[i] == nativeType) + return i; + i = (oslAddrFamily) ( i + 1 ); + } + + return i; +} + +/* macros */ +#define FAMILY_FROM_NATIVE(y) osl_AddrFamilyFromNative(y) +#define FAMILY_TO_NATIVE(x) (short)FamilyMap[x] + +/*****************************************************************************/ +/* enum oslProtocol */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 ProtocolMap[]= { + 0, /* osl_Socket_ProtocolIp */ + NSPROTO_IPX, /* osl_Socket_ProtocolIpx */ + NSPROTO_SPX, /* osl_Socket_ProtocolSpx */ + NSPROTO_SPXII, /* osl_Socket_ProtocolSpxII */ + 0 /* osl_Socket_ProtocolInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslProtocol osl_ProtocolFromNative(sal_uInt32 nativeType) +{ + oslProtocol i= (oslProtocol)0; + + while(i != osl_Socket_ProtocolInvalid) + { + if(ProtocolMap[i] == nativeType) + return i; + i = (oslProtocol) ( i + 1); + } + + return i; +} +*/ + +/* macros */ +#define PROTOCOL_FROM_NATIVE(y) osl_ProtocolFromNative(y) +#define PROTOCOL_TO_NATIVE(x) ProtocolMap[x] + + +/*****************************************************************************/ +/* enum oslSocketType */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 TypeMap[]= { + SOCK_STREAM, /* osl_Socket_TypeStream */ + SOCK_DGRAM, /* osl_Socket_TypeDgram */ + SOCK_RAW, /* osl_Socket_TypeRaw */ + SOCK_RDM, /* osl_Socket_TypeRdm */ + SOCK_SEQPACKET, /* osl_Socket_TypeSeqPacket */ + 0 /* osl_Socket_TypeInvalid */ +}; + +/* reverse map */ +static oslSocketType osl_SocketTypeFromNative(sal_uInt32 nativeType) +{ + oslSocketType i= (oslSocketType)0; + + while(i != osl_Socket_TypeInvalid) + { + if(TypeMap[i] == nativeType) + return i; + i = (oslSocketType)(i + 1); + } + + return i; +} + +/* macros */ +#define TYPE_TO_NATIVE(x) TypeMap[x] +#define TYPE_FROM_NATIVE(y) osl_SocketTypeFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketOption */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 OptionMap[]= { + SO_DEBUG, /* osl_Socket_OptionDebug */ + SO_ACCEPTCONN, /* osl_Socket_OptionAcceptConn */ + SO_REUSEADDR, /* osl_Socket_OptionReuseAddr */ + SO_KEEPALIVE, /* osl_Socket_OptionKeepAlive */ + SO_DONTROUTE, /* osl_Socket_OptionDontRoute */ + SO_BROADCAST, /* osl_Socket_OptionBroadcast */ + SO_USELOOPBACK, /* osl_Socket_OptionUseLoopback */ + SO_LINGER, /* osl_Socket_OptionLinger */ + SO_OOBINLINE, /* osl_Socket_OptionOOBinLine */ + SO_SNDBUF, /* osl_Socket_OptionSndBuf */ + SO_RCVBUF, /* osl_Socket_OptionRcvBuf */ + SO_SNDLOWAT, /* osl_Socket_OptionSndLowat */ + SO_RCVLOWAT, /* osl_Socket_OptionRcvLowat */ + SO_SNDTIMEO, /* osl_Socket_OptionSndTimeo */ + SO_RCVTIMEO, /* osl_Socket_OptionRcvTimeo */ + SO_ERROR, /* osl_Socket_OptionError */ + SO_TYPE, /* osl_Socket_OptionType */ + TCP_NODELAY, /* osl_Socket_OptionTcpNoDelay */ + 0 /* osl_Socket_OptionInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketOption osl_SocketOptionFromNative(sal_uInt32 nativeType) +{ + oslSocketOption i= (oslSocketOption)0; + + while(i != osl_Socket_OptionInvalid) + { + if(OptionMap[i] == nativeType) + return i; + i = (oslSocketOption) ( i + 1 ); + } + + return i; +} +*/ +/* macros */ +#define OPTION_TO_NATIVE(x) OptionMap[x] +#define OPTION_FROM_NATIVE(y) osl_SocketOptionFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketOptionLevel */ +/*****************************************************************************/ + +static sal_uInt32 OptionLevelMap[]= { + SOL_SOCKET, /* osl_Socket_LevelSocket */ + IPPROTO_TCP, /* osl_Socket_LevelTcp */ + 0 /* osl_Socket_LevelInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketOptionLevel osl_SocketOptionLevelFromNative(sal_uInt32 nativeType) +{ + oslSocketOptionLevel i= (oslSocketOptionLevel)0; + + while(i != osl_Socket_LevelInvalid) + { + if(OptionLevelMap[i] == nativeType) + return i; + i = (oslSocketOptionLevel) ( i + 1 ); + } + + return i; +} +*/ +/* macros */ +#define OPTION_LEVEL_TO_NATIVE(x) OptionLevelMap[x] +#define OPTION_LEVEL_FROM_NATIVE(y) osl_SocketOptionLevelFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketMsgFlag */ +/*****************************************************************************/ + +static sal_uInt32 SocketMsgFlagMap[]= { + 0, /* osl_Socket_MsgNormal */ + MSG_OOB, /* osl_Socket_MsgOOB */ + MSG_PEEK, /* osl_Socket_MsgPeek */ + MSG_DONTROUTE, /* osl_Socket_MsgDontRoute */ + MSG_MAXIOVLEN, /* osl_Socket_MsgMaxIOVLen */ + 0 /* osl_Socket_MsgInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketMsgFlag osl_SocketMsgFlagFromNative(sal_uInt32 nativeType) +{ + oslSocketMsgFlag i= (oslSocketMsgFlag)0; + + while(i != osl_Socket_MsgInvalid) + { + if(SocketMsgFlagMap[i] == nativeType) + return i; + i = (oslSocketMsgFlag) ( i + 1 ); + } + + return i; +} +*/ + +/* macros */ +#define MSG_FLAG_TO_NATIVE(x) SocketMsgFlagMap[x] +#define MSG_FLAG_FROM_NATIVE(y) osl_SocketMsgFlagFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketDirection */ +/*****************************************************************************/ + +static sal_uInt32 SocketDirection[]= { + SD_RECEIVE, /* osl_Socket_DirRead */ + SD_SEND, /* osl_Socket_DirWrite */ + SD_BOTH, /* osl_Socket_DirReadWrite */ + 0 /* osl_Socket_DirInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketDirection osl_SocketDirectionFromNative(sal_uInt32 nativeType) +{ + oslSocketDirection i= (oslSocketDirection)0; + + while(i != osl_Socket_DirInvalid) + { + if(SocketDirection[i] == nativeType) + return i; + i = (oslSocketDirection) ( i + 1 ); + } + + return i; +} +*/ + +/* macros */ +#define DIRECTION_TO_NATIVE(x) SocketDirection[x] +#define DIRECTION_FROM_NATIVE(y) osl_SocketDirectionFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketError */ +/*****************************************************************************/ + +static struct +{ + int errcode; + oslSocketError error; +} SocketError[]= { + { 0, osl_Socket_E_None }, /* no error */ + { ENOTSOCK, osl_Socket_E_NotSocket }, /* Socket operation on non-socket */ + { EDESTADDRREQ, osl_Socket_E_DestAddrReq }, /* Destination address required */ + { EMSGSIZE, osl_Socket_E_MsgSize }, /* Message too long */ + { EPROTOTYPE, osl_Socket_E_Prototype }, /* Protocol wrong type for socket */ + { ENOPROTOOPT, osl_Socket_E_NoProtocol }, /* Protocol not available */ + { EPROTONOSUPPORT, osl_Socket_E_ProtocolNoSupport }, /* Protocol not supported */ + { ESOCKTNOSUPPORT, osl_Socket_E_TypeNoSupport }, /* Socket type not supported */ + { EOPNOTSUPP, osl_Socket_E_OpNotSupport }, /* Operation not supported on socket */ + { EPFNOSUPPORT, osl_Socket_E_PfNoSupport }, /* Protocol family not supported */ + { EAFNOSUPPORT, osl_Socket_E_AfNoSupport }, /* Address family not supported by */ + /* protocol family */ + { EADDRINUSE, osl_Socket_E_AddrInUse }, /* Address already in use */ + { EADDRNOTAVAIL, osl_Socket_E_AddrNotAvail }, /* Can't assign requested address */ + { ENETDOWN, osl_Socket_E_NetDown }, /* Network is down */ + { ENETUNREACH, osl_Socket_E_NetUnreachable }, /* Network is unreachable */ + { ENETRESET, osl_Socket_E_NetReset }, /* Network dropped connection because */ + /* of reset */ + { ECONNABORTED, osl_Socket_E_ConnAborted }, /* Software caused connection abort */ + { ECONNRESET, osl_Socket_E_ConnReset }, /* Connection reset by peer */ + { ENOBUFS, osl_Socket_E_NoBufferSpace }, /* No buffer space available */ + { EISCONN, osl_Socket_E_IsConnected }, /* Socket is already connected */ + { ENOTCONN, osl_Socket_E_NotConnected }, /* Socket is not connected */ + { ESHUTDOWN, osl_Socket_E_Shutdown }, /* Can't send after socket shutdown */ + { ETOOMANYREFS, osl_Socket_E_TooManyRefs }, /* Too many references: can't splice */ + { ETIMEDOUT, osl_Socket_E_TimedOut }, /* Connection timed out */ + { ECONNREFUSED, osl_Socket_E_ConnRefused }, /* Connection refused */ + { EHOSTDOWN, osl_Socket_E_HostDown }, /* Host is down */ + { EHOSTUNREACH, osl_Socket_E_HostUnreachable }, /* No route to host */ + { EWOULDBLOCK, osl_Socket_E_WouldBlock }, /* call would block on non-blocking socket */ + { EALREADY, osl_Socket_E_Already }, /* operation already in progress */ + { EINPROGRESS, osl_Socket_E_InProgress }, /* operation now in progress */ + { EAGAIN, osl_Socket_E_WouldBlock }, /* same as EWOULDBLOCK */ + { -1, osl_Socket_E_InvalidError } +}; + +/* map */ +/* mfe: NOT USED +static int osl_NativeFromSocketError(oslSocketError errorCode) +{ + int i = 0; + + while ((SocketError[i].error != osl_Socket_E_InvalidError) && + (SocketError[i].error != errorCode)) i++; + + return SocketError[i].errcode; +} +*/ + +/* reverse map */ +static oslSocketError osl_SocketErrorFromNative(int nativeType) +{ + int i = 0; + + while ((SocketError[i].error != osl_Socket_E_InvalidError) && + (SocketError[i].errcode != nativeType)) i++; + + return SocketError[i].error; +} + +/* macros */ +#define ERROR_TO_NATIVE(x) osl_NativeFromSocketError(x) +#define ERROR_FROM_NATIVE(y) osl_SocketErrorFromNative(y) + +/*****************************************************************************/ +/* local function prototypes */ +/*****************************************************************************/ + +oslSocketAddr SAL_CALL osl_psz_createInetSocketAddr ( + const sal_Char* pszDottedAddr, sal_Int32 Port); + +oslSocketAddr SAL_CALL osl_psz_createIpxSocketAddr ( + const sal_Char NetNumber[4], + const sal_Char NodeNumber[6], + sal_uInt32 SocketNumber); + +oslHostAddr SAL_CALL osl_psz_createHostAddr ( + const sal_Char *pszHostname, const oslSocketAddr Addr); + +oslHostAddr SAL_CALL osl_psz_createHostAddrByName ( + const sal_Char *pszHostname); + +const sal_Char* SAL_CALL osl_psz_getHostnameOfHostAddr ( + const oslHostAddr Addr); + +oslSocketResult SAL_CALL osl_psz_getLocalHostname ( + sal_Char *pBuffer, sal_uInt32 nBufLen); + +oslSocketAddr SAL_CALL osl_psz_resolveHostname ( + const sal_Char* pszHostname); + +sal_Int32 SAL_CALL osl_psz_getServicePort ( + const sal_Char* pszServicename, const sal_Char* pszProtocol); + +oslSocketResult SAL_CALL osl_psz_getHostnameOfSocketAddr ( + oslSocketAddr Addr, sal_Char *pBuffer, sal_uInt32 BufferSize); + +oslSocketResult SAL_CALL osl_psz_getDottedInetAddrOfSocketAddr ( + oslSocketAddr Addr, sal_Char *pBuffer, sal_uInt32 BufferSize); + +void SAL_CALL osl_psz_getLastSocketErrorDescription ( + oslSocket Socket, sal_Char* pBuffer, sal_uInt32 BufferSize); + +/*****************************************************************************/ +/* osl_create/destroy-SocketImpl */ +/*****************************************************************************/ + +#if OSL_DEBUG_LEVEL > 1 +static sal_uInt32 g_nSocketImpl = 0; +static sal_uInt32 g_nSocketAddr = 0; + +/* sorry, must be implemented otherwise */ +#if 0 +struct LeakWarning +{ + ~LeakWarning() + { + if( g_nSocketImpl ) + OSL_TRACE( "sal_socket: %d socket instances leak\n" , g_nSocketImpl ); + if( g_nSocketAddr ) + OSL_TRACE( "sal_socket: %d socket address instances leak\n" , g_nSocketAddr ); + } +}; +LeakWarning socketWarning; +#endif + +#endif /* OSL_DEBUG_LEVEL */ + + +oslSocket __osl_createSocketImpl(int Socket) +{ + oslSocket pSocket; + + pSocket = (oslSocket)calloc(1, sizeof(struct oslSocketImpl)); + + pSocket->m_Socket = Socket; + pSocket->m_nLastError = 0; + pSocket->m_CloseCallback = 0; + pSocket->m_CallbackArg = 0; + pSocket->m_nRefCount = 1; + +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_False; +#endif + +#if OSL_DEBUG_LEVEL > 1 + g_nSocketImpl ++; +#endif + return pSocket; +} + +void __osl_destroySocketImpl(oslSocket Socket) +{ + if ( Socket != NULL) + free((struct oslSocketImpl *) Socket); +#if OSL_DEBUG_LEVEL > 1 + g_nSocketImpl --; +#endif +} + +static oslSocketAddr __osl_createSocketAddr( ) +{ + oslSocketAddr pAddr = (oslSocketAddr) rtl_allocateZeroMemory( sizeof( struct oslSocketAddrImpl )); +#if OSL_DEBUG_LEVEL > 1 + g_nSocketAddr ++; +#endif + return pAddr; +} + +static oslSocketAddr __osl_createSocketAddrWithFamily( + oslAddrFamily family, sal_Int32 port, sal_uInt32 nAddr ) +{ + oslSocketAddr pAddr; + + OSL_ASSERT( family == osl_Socket_FamilyInet ); + + pAddr = __osl_createSocketAddr(); + switch( family ) + { + case osl_Socket_FamilyInet: + { + struct sockaddr_in* pInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + pInetAddr->sin_family = FAMILY_TO_NATIVE(osl_Socket_FamilyInet); + pInetAddr->sin_addr.s_addr = nAddr; + pInetAddr->sin_port = (sal_uInt16)(port&0xffff); + break; + } + default: + pAddr->m_sockaddr.sa_family = FAMILY_TO_NATIVE(family); + } + return pAddr; +} + +static oslSocketAddr __osl_createSocketAddrFromSystem( struct sockaddr *pSystemSockAddr ) +{ + oslSocketAddr pAddr = __osl_createSocketAddr(); + memcpy( &(pAddr->m_sockaddr), pSystemSockAddr, sizeof( struct sockaddr ) ); + return pAddr; +} + +static void __osl_destroySocketAddr( oslSocketAddr addr ) +{ +#if OSL_DEBUG_LEVEL > 1 + g_nSocketAddr --; +#endif + rtl_freeMemory( addr ); +} + +/*****************************************************************************/ +/* osl_createEmptySocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createEmptySocketAddr(oslAddrFamily Family) +{ + oslSocketAddr pAddr = 0; + + /* is it an internet-Addr? */ + if (Family == osl_Socket_FamilyInet) + { + pAddr = __osl_createSocketAddrWithFamily(Family, 0 , htonl(INADDR_ANY) ); + } + else + { + pAddr = __osl_createSocketAddrWithFamily( Family , 0 , 0 ); + } + + return pAddr; +} + +/*****************************************************************************/ +/* osl_copySocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_copySocketAddr(oslSocketAddr Addr) +{ + oslSocketAddr pCopy = 0; + if (Addr) + { + pCopy = __osl_createSocketAddr(); + + if (pCopy) + memcpy(&(pCopy->m_sockaddr),&(Addr->m_sockaddr), sizeof(struct sockaddr)); + } + return pCopy; +} + +/*****************************************************************************/ +/* osl_isEqualSocketAddr */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isEqualSocketAddr ( + oslSocketAddr Addr1, + oslSocketAddr Addr2) +{ + struct sockaddr* pAddr1= &(Addr1->m_sockaddr); + struct sockaddr* pAddr2= &(Addr2->m_sockaddr); + + OSL_ASSERT(pAddr1); + OSL_ASSERT(pAddr2); + + if (pAddr1->sa_family == pAddr2->sa_family) + { + switch (pAddr1->sa_family) + { + case AF_INET: + { + struct sockaddr_in* pInetAddr1= (struct sockaddr_in*)pAddr1; + struct sockaddr_in* pInetAddr2= (struct sockaddr_in*)pAddr2; + + if ((pInetAddr1->sin_family == pInetAddr2->sin_family) && + (pInetAddr1->sin_addr.s_addr == pInetAddr2->sin_addr.s_addr) && + (pInetAddr1->sin_port == pInetAddr2->sin_port)) + return (sal_True); + } + + default: + { + return (memcmp(pAddr1, Addr2, sizeof(struct sockaddr)) == 0); + } + } + } + + return (sal_False); +} + +/*****************************************************************************/ +/* osl_createInetBroadcastAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createInetBroadcastAddr ( + rtl_uString *strDottedAddr, + sal_Int32 Port) +{ + sal_uInt32 nAddr = OSL_INADDR_NONE; + oslSocketAddr pAddr; + + if (strDottedAddr && strDottedAddr->length) + { + /* Dotted host address for limited broadcast */ + rtl_String *pDottedAddr = NULL; + + rtl_uString2String ( + &pDottedAddr, strDottedAddr->buffer, strDottedAddr->length, + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + + nAddr = inet_addr (pDottedAddr->buffer); + rtl_string_release (pDottedAddr); + } + + if (nAddr != OSL_INADDR_NONE) + { + /* Limited broadcast */ + nAddr = ntohl(nAddr); + if (IN_CLASSA(nAddr)) + { + nAddr &= IN_CLASSA_NET; + nAddr |= IN_CLASSA_HOST; + } + else if (IN_CLASSB(nAddr)) + { + nAddr &= IN_CLASSB_NET; + nAddr |= IN_CLASSB_HOST; + } + else if (IN_CLASSC(nAddr)) + { + nAddr &= IN_CLASSC_NET; + nAddr |= IN_CLASSC_HOST; + } + else + { + /* No broadcast in class D */ + return ((oslSocketAddr)NULL); + } + nAddr = htonl(nAddr); + } + + pAddr = __osl_createSocketAddrWithFamily( osl_Socket_FamilyInet, htons(Port), nAddr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_createInetSocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createInetSocketAddr ( + rtl_uString *ustrDottedAddr, + sal_Int32 Port) +{ + rtl_String* strDottedAddr=0; + oslSocketAddr Addr; + sal_Char* pszDottedAddr=0; + + if ( ustrDottedAddr != 0 ) + { + rtl_uString2String( &strDottedAddr, + rtl_uString_getStr(ustrDottedAddr), + rtl_uString_getLength(ustrDottedAddr), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS); + pszDottedAddr = rtl_string_getStr(strDottedAddr); + } + + + Addr = osl_psz_createInetSocketAddr(pszDottedAddr, Port); + + if ( strDottedAddr != 0 ) + { + rtl_string_release(strDottedAddr); + } + + return Addr; +} + +oslSocketAddr SAL_CALL osl_psz_createInetSocketAddr ( + const sal_Char* pszDottedAddr, + sal_Int32 Port) +{ + oslSocketAddr pAddr = 0; + sal_Int32 Addr = inet_addr(pszDottedAddr); + if(Addr != -1) + { + /* valid dotted addr */ + pAddr = __osl_createSocketAddrWithFamily( osl_Socket_FamilyInet, htons(Port) , Addr ); + } + return pAddr; +} + +/*****************************************************************************/ +/* osl_setAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_setAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence *pByteSeq ) +{ + oslSocketResult res = osl_Socket_Error; + + OSL_ASSERT( pAddr ); + OSL_ASSERT( pByteSeq ); + + if( pAddr && pByteSeq ) + { + struct sockaddr_in * pSystemInetAddr; + + OSL_ASSERT( pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE( osl_Socket_FamilyInet ) ); + OSL_ASSERT( pByteSeq->nElements == 4 ); + + pSystemInetAddr = (struct sockaddr_in * ) &(pAddr->m_sockaddr); + memcpy( &(pSystemInetAddr->sin_addr) , pByteSeq->elements , 4 ); + res = osl_Socket_Ok; + } + return res; +} + +/*****************************************************************************/ +/* osl_getAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence **ppByteSeq ) +{ + oslSocketResult res = osl_Socket_Error; + + OSL_ASSERT( pAddr ); + OSL_ASSERT( ppByteSeq ); + + if( pAddr && ppByteSeq ) + { + struct sockaddr_in * pSystemInetAddr = (struct sockaddr_in * ) &(pAddr->m_sockaddr); + rtl_byte_sequence_constructFromArray( ppByteSeq , (sal_Int8 *) &(pSystemInetAddr->sin_addr),4); + res = osl_Socket_Ok; + } + return res; +} + + +/*****************************************************************************/ +/* _osl_getFullQualifiedDomainName */ +/*****************************************************************************/ + +/** try to figure out a full-qualified hostname, by adding the current domain + as given by the domainname program to the given hostname. + This function MUST NOT call gethostbyname since pHostName allready points + to data returned by gethostname and would be garbled: use gethostname_r + instead! + */ + +/* wrap around different interfaces to reentrant gethostbyname */ +static struct hostent* _osl_gethostbyname_r ( + const char *name, struct hostent *result, + char *buffer, int buflen, int *h_errnop) +{ +#if defined(LINUX) || (defined(FREEBSD) && (__FreeBSD_version >= 601103)) + struct hostent *__result; /* will be the same as result */ + int __error; + __error = gethostbyname_r (name, result, buffer, buflen, + &__result, h_errnop); + return __error ? NULL : __result ; +#else + return gethostbyname_r( name, result, buffer, buflen, h_errnop); +#endif +} + +static sal_Bool _osl_getDomainName (sal_Char *buffer, sal_Int32 bufsiz) +{ + sal_Bool result; + int p[2]; + + result = sal_False; + if (pipe (p) == 0) + { + pid_t pid; + int nStatus; + + pid = fork(); + if (pid == 0) + { + char *argv[] = + { + "/bin/domainname", + NULL + }; + + close (p[0]); + dup2 (p[1], 1); + close (p[1]); + + execv ("/bin/domainname", argv); + // arriving here means exec failed + _exit(-1); + } + else if (pid > 0) + { + sal_Int32 k = 0, n = bufsiz; + + close (p[1]); + if ((k = read (p[0], buffer, n - 1)) > 0) + { + buffer[k] = 0; + if (buffer[k - 1] == '\n') + buffer[k - 1] = 0; + result = sal_True; + } + close (p[0]); + waitpid (pid, &nStatus, 0); + } + else + { + close (p[0]); + close (p[1]); + } + } + return (result); +} + +static sal_Char* _osl_getFullQualifiedDomainName (const sal_Char *pHostName) +{ +# define DOMAINNAME_LENGTH 512 + sal_uInt32 nLengthOfHostName; + static sal_uInt32 nLengthOfDomainName = 0; + static sal_Char *pDomainName = NULL; + + sal_Char *pFullQualifiedName; +#if 0 /* OBSOLETE */ + FILE *pPipeToDomainnameExe; +#endif /* OBSOLETE */ + + /* get a '\0' terminated domainname */ + + /* read default domainname default from environment */ + if (nLengthOfDomainName == 0) + { + sal_Char *pEnvDomain; + + pEnvDomain = getenv ("STAR_OVERRIDE_DOMAINNAME"); + if (pEnvDomain) + { + pDomainName = strdup (pEnvDomain); + nLengthOfDomainName = strlen (pDomainName); + } + } + +#if 1 /* NEW */ + if (nLengthOfDomainName == 0) + { + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + + pDomainNameBuffer[0] = '\0'; + + if (_osl_getDomainName (pDomainNameBuffer, DOMAINNAME_LENGTH)) + { + pDomainName = strdup (pDomainNameBuffer); + nLengthOfDomainName = strlen (pDomainName); + } + } + +#endif /* NEW */ +#if 0 /* OBSOLETE */ +#ifdef SCO + + /* call 'domainname > /usr/tmp/some-tmp-file', since + popen read pclose do block or core-dump, + (even the pipe-stuff that comes with pthreads) */ + if (nLengthOfDomainName == 0) + { + sal_Char tmp_name[ L_tmpnam ]; + FILE *tmp_file; + sal_Char domain_call [ L_tmpnam + 16 ] = "domainname > "; + + tmp_name[0] = '\0'; + + tmpnam ( tmp_name ); + strcat ( domain_call, tmp_name ); + if ( (system ( domain_call ) == 0) + && ((tmp_file = fopen( tmp_name, "r" )) != NULL ) ) + { + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + + pDomainNameBuffer[0] = '\0'; + + if ( fgets ( pDomainNameBuffer, DOMAINNAME_LENGTH, tmp_file ) ) + { + pDomainName = strdup( pDomainNameBuffer ); + nLengthOfDomainName = strlen( pDomainName ); + if ( ( nLengthOfDomainName > 0 ) + && ( pDomainName[ nLengthOfDomainName - 1] == '\n' ) ) + pDomainName[ --nLengthOfDomainName ] = '\0'; + } + fclose ( tmp_file ); + } + unlink( tmp_name ); + } + +#else /* !SCO */ + + /* read the domainname from pipe to the program domainname */ + if ( (nLengthOfDomainName == 0) + && (pPipeToDomainnameExe = popen( "domainname", "r")) ) + { + sal_Char c; + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + sal_Char *pDomainNamePointer; + + pDomainNameBuffer[0] = '\0'; + + pDomainNamePointer = pDomainNameBuffer; + while ( ((c = getc( pPipeToDomainnameExe )) != EOF) + && (nLengthOfDomainName < (DOMAINNAME_LENGTH - 1)) ) + { + if (! isspace(c)) + { + nLengthOfDomainName++ ; + *pDomainNamePointer++ = (sal_Char)c; + } + } + *pDomainNamePointer = '\0'; + pDomainName = strdup( pDomainNameBuffer ); + + pclose( pPipeToDomainnameExe ); + } + +#endif /* !SCO */ +#endif /* OBSOLETE */ + + /* compose hostname and domainname */ + nLengthOfHostName = strlen( pHostName ); + pFullQualifiedName = (sal_Char*) malloc( (nLengthOfHostName + 1 + + nLengthOfDomainName + 1) * sizeof(sal_Char) ); + memcpy( pFullQualifiedName, pHostName, + (nLengthOfHostName + 1) * sizeof(sal_Char) ); + + if ( nLengthOfDomainName > 0 ) + { + /* fqdn = hostname + '.' + domainname + '\0' */ + pFullQualifiedName[ nLengthOfHostName ] = '.'; + memcpy( pFullQualifiedName + nLengthOfHostName + 1, pDomainName, + nLengthOfDomainName + 1 ); + } + + /* check whether full-qualified name and hostname point to the same host + * should almost always be true */ + if ( nLengthOfDomainName > 0 ) + { + struct hostent *pQualifiedHostByName; + struct hostent *pHostByName; + sal_Bool bHostsAreEqual; + + /* buffer for calls to reentrant version of gethostbyname */ + struct hostent aHostByName, aQualifiedHostByName; + sal_Char pHostBuffer[ MAX_HOSTBUFFER_SIZE ]; + sal_Char pQualifiedHostBuffer[ MAX_HOSTBUFFER_SIZE ]; + int nErrorNo; + + pHostBuffer[0] = '\0'; + pQualifiedHostBuffer[0] = '\0'; + + /* get list of addresses */ + pQualifiedHostByName = _osl_gethostbyname_r ( + pFullQualifiedName, + &aQualifiedHostByName, pQualifiedHostBuffer, + sizeof(pQualifiedHostBuffer), &nErrorNo ); + pHostByName = _osl_gethostbyname_r ( + pHostName, + &aHostByName, pHostBuffer, + sizeof(pHostBuffer), &nErrorNo ); + + /* compare addresses */ + bHostsAreEqual = sal_False; + if ( pQualifiedHostByName && pHostByName ) + { + sal_Char **p, **q; + struct in_addr in; + + /* lists are expected to be (very) short */ + for ( p = pQualifiedHostByName->h_addr_list; *p != NULL; p++ ) + { + for ( q = pHostByName->h_addr_list; *q != NULL; q++ ) + { + /* in.s_addr may be in_addr_t or uint32_t or heaven knows */ + if ( memcmp( *p, *q, sizeof(in.s_addr) ) == 0 ) + { + bHostsAreEqual = sal_True; + break; + } + } + if ( bHostsAreEqual ) + break; + } + } + + /* very strange case, but have to believe it: reduce the + * full qualified name to the unqualified host name */ + if ( !bHostsAreEqual ) + { + OSL_TRACE("_osl_getFullQualifiedDomainName: " + "suspect FQDN: %s\n", pFullQualifiedName); + + pFullQualifiedName[ nLengthOfHostName ] = '\0'; + pFullQualifiedName = (sal_Char*)realloc ( pFullQualifiedName, + (nLengthOfHostName + 1) * sizeof( sal_Char )); + } + } + + /* always return a hostname looked up as carefully as possible + * this string must be freed by the caller */ + return pFullQualifiedName; +} + +/*****************************************************************************/ +/* _osl_isFullQualifiedDomainName */ +/*****************************************************************************/ +static sal_Bool _osl_isFullQualifiedDomainName (const sal_Char *pHostName) +{ + /* a FQDN (aka 'hostname.domain.top_level_domain' ) + * is a name which contains a dot '.' in it ( would + * match as well for 'hostname.' but is good enough + * for now )*/ + return (sal_Bool)( strchr( pHostName, (int)'.' ) != NULL ); +} + +/*****************************************************************************/ +/* oslHostAddr */ +/*****************************************************************************/ +struct oslHostAddrImpl +{ + sal_Char *pHostName; + oslSocketAddr pSockAddr; +}; + +static oslHostAddr _osl_hostentToHostAddr (const struct hostent *he) +{ + oslHostAddr pAddr= NULL; + oslSocketAddr pSockAddr = 0; + + sal_Char *cn; + + if ((he == NULL) || (he->h_name == NULL) || (he->h_addr_list[0] == NULL)) + return ((oslHostAddr)NULL); + + if (_osl_isFullQualifiedDomainName(he->h_name)) + { + cn= (sal_Char *)malloc(strlen (he->h_name) + 1); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + + strcpy(cn, he->h_name); + } + else + { + cn =_osl_getFullQualifiedDomainName (he->h_name); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + } + + pSockAddr = __osl_createSocketAddr(); + OSL_ASSERT(pSockAddr); + if (pSockAddr == NULL) + { + free(cn); + return ((oslHostAddr)NULL); + } + + pSockAddr->m_sockaddr.sa_family= he->h_addrtype; + if (pSockAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + struct sockaddr_in *sin= (struct sockaddr_in *)&(pSockAddr->m_sockaddr); + memcpy ( + &(sin->sin_addr.s_addr), + he->h_addr_list[0], + he->h_length); + } + else + { + /* unknown address family */ + /* future extensions for new families might be implemented here */ + + OSL_TRACE("_osl_hostentToHostAddr: unknown address family.\n"); + OSL_ASSERT(sal_False); + + __osl_destroySocketAddr( pSockAddr ); + free (cn); + return ((oslHostAddr)NULL); + } + + pAddr= (oslHostAddr) malloc(sizeof(struct oslHostAddrImpl)); + OSL_ASSERT(pAddr); + if (pAddr == NULL) + { + __osl_destroySocketAddr( pSockAddr ); + free (cn); + return ((oslHostAddr)NULL); + } + + pAddr->pHostName= cn; + pAddr->pSockAddr= pSockAddr; + + return pAddr; +} + +/*****************************************************************************/ +/* osl_createHostAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddr ( + rtl_uString *ustrHostname, + const oslSocketAddr Addr) +{ + oslHostAddr HostAddr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName = rtl_string_getStr(strHostname); + } + + HostAddr = osl_psz_createHostAddr(pszHostName,Addr); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + + return HostAddr; +} + +oslHostAddr SAL_CALL osl_psz_createHostAddr ( + const sal_Char *pszHostname, + const oslSocketAddr pAddr) +{ + oslHostAddr pHostAddr; + sal_Char *cn; + + OSL_ASSERT(pszHostname && pAddr); + if ((pszHostname == NULL) || (pAddr == NULL)) + return ((oslHostAddr)NULL); + + cn = (sal_Char *)malloc(strlen (pszHostname) + 1); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + + strcpy (cn, pszHostname); + + pHostAddr= (oslHostAddr) malloc(sizeof(struct oslHostAddrImpl)); + OSL_ASSERT(pHostAddr); + if (pAddr == NULL) + { + free (cn); + return ((oslHostAddr)NULL); + } + + pHostAddr->pHostName= cn; + pHostAddr->pSockAddr= osl_copySocketAddr( pAddr ); + + return pHostAddr; +} + +/*****************************************************************************/ +/* osl_createHostAddrByName */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddrByName(rtl_uString *ustrHostname) +{ + oslHostAddr HostAddr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName=rtl_string_getStr(strHostname); + } + + HostAddr = osl_psz_createHostAddrByName(pszHostName); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + return HostAddr; +} + +oslHostAddr SAL_CALL osl_psz_createHostAddrByName (const sal_Char *pszHostname) +{ + struct hostent *he; + oslHostAddr addr; + + static oslMutex mutex = NULL; + + if (mutex == NULL) + mutex = osl_createMutex(); + + osl_acquireMutex(mutex); + + he = gethostbyname((sal_Char *)pszHostname); + addr = _osl_hostentToHostAddr (he); + + osl_releaseMutex(mutex); + + return addr; +} + +/*****************************************************************************/ +/* osl_createHostAddrByAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddrByAddr (const oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr == NULL) + return ((oslHostAddr)NULL); + + if (pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + const struct sockaddr_in *sin= (const struct sockaddr_in *)&(pAddr->m_sockaddr); + struct hostent *he; + + if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) + return ((oslHostAddr)NULL); + + he= gethostbyaddr((sal_Char *)&(sin->sin_addr), + sizeof (sin->sin_addr), + sin->sin_family); + return _osl_hostentToHostAddr (he); + } + + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_copyHostAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_copyHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return osl_psz_createHostAddr (pAddr->pHostName, pAddr->pSockAddr); + else + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_getHostnameOfHostAddr */ +/*****************************************************************************/ +void SAL_CALL osl_getHostnameOfHostAddr ( + const oslHostAddr Addr, + rtl_uString **ustrHostname) +{ + const sal_Char* pHostname=0; + + pHostname = osl_psz_getHostnameOfHostAddr(Addr); + + rtl_uString_newFromAscii (ustrHostname, pHostname); + + return; +} + +const sal_Char* SAL_CALL osl_psz_getHostnameOfHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return pAddr->pHostName; + else + return NULL; +} + +/*****************************************************************************/ +/* osl_getSocketAddrOfHostAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getSocketAddrOfHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return ((oslSocketAddr)(pAddr->pSockAddr)); + else + return NULL; +} + +/*****************************************************************************/ +/* osl_destroyHostAddr */ +/*****************************************************************************/ +void SAL_CALL osl_destroyHostAddr (oslHostAddr pAddr) +{ + if (pAddr) + { + if (pAddr->pHostName) + free (pAddr->pHostName); + if (pAddr->pSockAddr) + osl_destroySocketAddr (pAddr->pSockAddr); + free (pAddr); + } +} + +/*****************************************************************************/ +/* osl_getLocalHostname */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getLocalHostname(rtl_uString **ustrLocalHostname) +{ + oslSocketResult Result; + sal_Char pszHostname[1024]; + + pszHostname[0] = '\0'; + + Result = osl_psz_getLocalHostname(pszHostname,sizeof(pszHostname)); + + rtl_uString_newFromAscii(ustrLocalHostname,pszHostname); + + return Result; +} + +oslSocketResult SAL_CALL osl_psz_getLocalHostname ( + sal_Char *pBuffer, sal_uInt32 nBufLen) +{ + static sal_Char LocalHostname[256] = ""; + + if (strlen(LocalHostname) == 0) + { + const sal_Char *pStr; + +#ifdef SYSV + struct utsname uts; + + if (uname(&uts) < 0) + return osl_Socket_Error; + + if ((strlen(uts.nodename) + 1) > nBufLen) + return osl_Socket_Error; + + strncpy(LocalHostname, uts.nodename, sizeof( LocalHostname )); +#else /* BSD compatible */ + + if (gethostname(LocalHostname, sizeof(LocalHostname)-1) != 0) + return osl_Socket_Error; + LocalHostname[sizeof(LocalHostname)-1] = 0; +#endif /* SYSV */ + + /* check if we have an FQDN */ + if (strchr(LocalHostname, '.') == NULL) + { + oslHostAddr Addr; + + /* no, determine it via dns */ + Addr = osl_psz_createHostAddrByName(LocalHostname); + + if ((pStr = osl_psz_getHostnameOfHostAddr(Addr)) != NULL) + { +#if 0 /* OBSOLETE */ + sal_Char* pChr; +#endif /* OBSOLETE */ + strcpy(LocalHostname, pStr); + +#if 0 /* OBSOLETE */ + /* already done by _osl_getFullQualifiedDomainName() with + much better heuristics, so this may be contraproductive */ + + /* no FQDN, last try append domain name */ + if ((pChr = strchr(LocalHostname, '.')) == NULL) + { + FILE *fp; + + pChr = &LocalHostname[strlen(LocalHostname)]; + + if ( (fp = popen("domainname", "r")) != 0 ) + { + int c; + + *pChr++ = '.'; + + while ((c = getc(fp)) != EOF) + { + if (! isspace(c)) + *pChr++ = (sal_Char)c; + } + + *pChr = '\0'; + + fclose(fp); + } + else + LocalHostname[0] = '\0'; + } +#endif /* OBSOLETE */ + + } + osl_destroyHostAddr(Addr); + } + } + + if (strlen(LocalHostname) > 0) + { + strncpy(pBuffer, LocalHostname, nBufLen); + pBuffer[nBufLen - 1] = '\0'; + + return osl_Socket_Ok; + } + + return osl_Socket_Error; +} + +/*****************************************************************************/ +/* osl_resolveHostname */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_resolveHostname(rtl_uString *ustrHostname) +{ + oslSocketAddr Addr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName = rtl_string_getStr(strHostname); + } + + + Addr = osl_psz_resolveHostname(pszHostName); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + + return Addr; +} + + +oslSocketAddr SAL_CALL osl_psz_resolveHostname(const sal_Char* pszHostname) +{ + struct oslHostAddrImpl *pAddr = (oslHostAddr)osl_psz_createHostAddrByName(pszHostname); + + if (pAddr) + { + oslSocketAddr SockAddr = osl_copySocketAddr(pAddr->pSockAddr); + + osl_destroyHostAddr(pAddr); + + return (SockAddr); + } + + return ((oslSocketAddr)NULL); +} + +/*****************************************************************************/ +/* osl_getServicePort */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getServicePort(rtl_uString *ustrServicename, rtl_uString *ustrProtocol) +{ + sal_Int32 nPort; + rtl_String* strServicename=0; + rtl_String* strProtocol=0; + sal_Char* pszServiceName=0; + sal_Char* pszProtocol=0; + + if ( ustrServicename != 0 ) + { + rtl_uString2String( &strServicename, + rtl_uString_getStr(ustrServicename), + rtl_uString_getLength(ustrServicename), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszServiceName = rtl_string_getStr(strServicename); + } + + if ( ustrProtocol != 0 ) + { + rtl_uString2String( &strProtocol, + rtl_uString_getStr(ustrProtocol), + rtl_uString_getLength(ustrProtocol), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszProtocol = rtl_string_getStr(strProtocol); + } + + nPort = osl_psz_getServicePort(pszServiceName,pszProtocol); + + if ( strServicename != 0 ) + { + rtl_string_release(strServicename); + } + + if ( strProtocol != 0 ) + { + rtl_string_release(strProtocol); + } + + + return nPort; +} + + +sal_Int32 SAL_CALL osl_psz_getServicePort(const sal_Char* pszServicename, + const sal_Char* pszProtocol) +{ + struct servent* ps; + + ps= getservbyname(pszServicename, pszProtocol); + + if (ps != 0) + return ntohs(ps->s_port); + + return OSL_INVALID_PORT; +} + +/*****************************************************************************/ +/* osl_destroySocketAddr */ +/*****************************************************************************/ +void SAL_CALL osl_destroySocketAddr(oslSocketAddr pAddr) +{ + __osl_destroySocketAddr( pAddr ); +} + +/*****************************************************************************/ +/* osl_getFamilyOfSocketAddr */ +/*****************************************************************************/ +oslAddrFamily SAL_CALL osl_getFamilyOfSocketAddr(oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return FAMILY_FROM_NATIVE(pAddr->m_sockaddr.sa_family); + else + return osl_Socket_FamilyInvalid; +} + +/*****************************************************************************/ +/* osl_getInetPortOfSocketAddr */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getInetPortOfSocketAddr(oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + if ( pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + return ntohs(pSystemInetAddr->sin_port); + } + return OSL_INVALID_PORT; +} + +/*****************************************************************************/ +/* osl_setInetPortOfSocketAddr */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setInetPortOfSocketAddr(oslSocketAddr pAddr, sal_Int32 Port) +{ + OSL_ASSERT(pAddr); + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + if ( pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + pSystemInetAddr->sin_port= htons((short)Port); + return sal_True; + } + } + + /* this is not a inet-addr => can't set port */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_getHostnameOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getHostnameOfSocketAddr(oslSocketAddr Addr, rtl_uString **ustrHostname) +{ + oslSocketResult Result; + sal_Char pszHostname[1024]; + + pszHostname[0] = '\0'; + + Result = osl_psz_getHostnameOfSocketAddr(Addr,pszHostname,sizeof(pszHostname)); + + rtl_uString_newFromAscii(ustrHostname,pszHostname); + + return Result; +} + + +oslSocketResult SAL_CALL osl_psz_getHostnameOfSocketAddr(oslSocketAddr pAddr, + sal_Char *pBuffer, sal_uInt32 BufferSize) +{ + oslHostAddr pHostAddr= (oslHostAddr )osl_createHostAddrByAddr(pAddr); + + if (pHostAddr) + { + strncpy(pBuffer, pHostAddr->pHostName, BufferSize); + + pBuffer[BufferSize - 1] = '\0'; + + osl_destroyHostAddr(pHostAddr); + + return osl_Socket_Ok; + } + + return osl_Socket_Error; +} + +/*****************************************************************************/ +/* osl_getDottedInetAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getDottedInetAddrOfSocketAddr(oslSocketAddr Addr, rtl_uString **ustrDottedInetAddr) +{ + oslSocketResult Result; + sal_Char pszDottedInetAddr[1024]; + + pszDottedInetAddr[0] = '\0'; + + Result = osl_psz_getDottedInetAddrOfSocketAddr(Addr,pszDottedInetAddr,sizeof(pszDottedInetAddr)); + + rtl_uString_newFromAscii(ustrDottedInetAddr,pszDottedInetAddr); + + return Result; + +} + +oslSocketResult SAL_CALL osl_psz_getDottedInetAddrOfSocketAddr(oslSocketAddr pAddr, + sal_Char *pBuffer, sal_uInt32 BufferSize) +{ + OSL_ASSERT(pAddr); + + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr = ( struct sockaddr_in * ) &(pAddr->m_sockaddr); + + if (pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + strncpy(pBuffer, inet_ntoa(pSystemInetAddr->sin_addr), BufferSize); + pBuffer[BufferSize - 1] = '\0'; + + return osl_Socket_Ok; + } + } + + return osl_Socket_Error; +} + +#if 0 /* OBSOLETE */ +/*****************************************************************************/ +/* osl_getIpxNetNumber */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getIpxNetNumber(oslSocketAddr Addr, + oslSocketIpxNetNumber NetNumber) + +{ + struct sockaddr_ipx* pAddr; + + pAddr= (struct sockaddr_ipx*)Addr; + + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + { + memcpy(NetNumber, pAddr->sa_netnum, sizeof(NetNumber)); + + return osl_Socket_Ok; + } + else + return osl_Socket_Error; +} + + +/*****************************************************************************/ +/* osl_getIpxNodeNumber */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getIpxNodeNumber(oslSocketAddr Addr, + oslSocketIpxNodeNumber NodeNumber) + +{ + struct sockaddr_ipx* pAddr; + + pAddr= (struct sockaddr_ipx*)Addr; + + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + { + memcpy(NodeNumber, pAddr->sa_nodenum, sizeof(NodeNumber)); + + return osl_Socket_Ok; + } + else + return osl_Socket_Error; +} + + +/*****************************************************************************/ +/* osl_getIpxSocketNumber */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getIpxSocketNumber(oslSocketAddr Addr) +{ + struct sockaddr_ipx* pAddr= (struct sockaddr_ipx*)Addr; + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + return pAddr->sa_socket; + else + return OSL_INVALID_IPX_SOCKET_NO; +} + +#endif /* OBSOLETE */ + +/*****************************************************************************/ +/* osl_createSocket */ +/*****************************************************************************/ +oslSocket SAL_CALL osl_createSocket(oslAddrFamily Family, + oslSocketType Type, + oslProtocol Protocol) +{ + int Flags; + oslSocket pSocket; + + /* alloc memory */ + pSocket= __osl_createSocketImpl(OSL_INVALID_SOCKET); + + /* create socket */ + pSocket->m_Socket= socket(FAMILY_TO_NATIVE(Family), + TYPE_TO_NATIVE(Type), + PROTOCOL_TO_NATIVE(Protocol)); + + /* creation failed => free memory */ + if(pSocket->m_Socket == OSL_INVALID_SOCKET) + { + OSL_TRACE("osl_createSocket failed. Errno: %d; %s\n", + errno, + strerror(errno)); + + __osl_destroySocketImpl((pSocket)); + pSocket= 0; + } + else + { + /* set close-on-exec flag */ + if ((Flags = fcntl(pSocket->m_Socket, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + if (fcntl(pSocket->m_Socket, F_SETFD, Flags) == -1) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_createSocket failed changing socket flags. Errno: %d; %s\n", + errno, + strerror(errno)); + } + } + else + { + pSocket->m_nLastError=errno; + } + + + pSocket->m_CloseCallback = NULL; + pSocket->m_CallbackArg = NULL; + } + + return pSocket; +} + +void SAL_CALL osl_acquireSocket(oslSocket pSocket) +{ + osl_incrementInterlockedCount( &(pSocket->m_nRefCount ) ); +} + +void SAL_CALL osl_releaseSocket( oslSocket pSocket ) +{ + if( pSocket && 0 == osl_decrementInterlockedCount( &(pSocket->m_nRefCount) ) ) + { +#if defined(LINUX) + if ( pSocket->m_bIsAccepting == sal_True ) + { + OSL_ENSURE(0, "osl_destroySocket : attempt to destroy socket while accepting\n"); + return; + } +#endif /* LINUX */ + osl_closeSocket( pSocket ); + __osl_destroySocketImpl( pSocket ); + } +} + + + +/*****************************************************************************/ +/* osl_closeSocket */ +/*****************************************************************************/ +void SAL_CALL osl_closeSocket(oslSocket pSocket) +{ + int nRet; + int nFD; + + /* socket already invalid */ + if(pSocket==0) + return; + + pSocket->m_nLastError=0; + nFD = pSocket->m_Socket; + + if (nFD == OSL_INVALID_SOCKET) + return; + + pSocket->m_Socket = OSL_INVALID_SOCKET; + +#if defined(LINUX) + pSocket->m_bIsInShutdown = sal_True; + + if ( pSocket->m_bIsAccepting == sal_True ) + { + int nConnFD; + union { + struct sockaddr aSockAddr; + struct sockaddr_in aSockAddrIn; + } s; + socklen_t nSockLen = sizeof(s.aSockAddr); + + nRet = getsockname(nFD, &s.aSockAddr, &nSockLen); +#if OSL_DEBUG_LEVEL > 1 + if ( nRet < 0 ) + { + perror("getsockname"); + } +#endif /* OSL_DEBUG_LEVEL */ + + if ( s.aSockAddr.sa_family == AF_INET ) + { + if ( s.aSockAddrIn.sin_addr.s_addr == htonl(INADDR_ANY) ) + { + s.aSockAddrIn.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + + nConnFD = socket(AF_INET, SOCK_STREAM, 0); +#if OSL_DEBUG_LEVEL > 1 + if ( nConnFD < 0 ) + { + perror("socket"); + } +#endif /* OSL_DEBUG_LEVEL */ + + nRet = connect(nConnFD, &s.aSockAddr, sizeof(s.aSockAddr)); +#if OSL_DEBUG_LEVEL > 1 + if ( nRet < 0 ) + { + perror("connect"); + } +#endif /* OSL_DEBUG_LEVEL */ + close(nConnFD); + } + pSocket->m_bIsAccepting = sal_False; + } +#endif /* LINUX */ + + /* registrierten Callback ausfuehren */ + if (pSocket->m_CloseCallback != NULL) + { + pSocket->m_CloseCallback(pSocket->m_CallbackArg); + } + + nRet=close(nFD); + if ( nRet != 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("closeSocket close error '%s'\n",strerror(errno)); + } + + pSocket->m_Socket = OSL_INVALID_SOCKET; +} + +/*****************************************************************************/ +/* osl_getLocalAddrOfSocket */ +/* Note that I rely on the fact that oslSocketAddr and struct sockaddr */ +/* are the same! I don't like it very much but see no other easy way to conceal */ +/* the struct sockaddr from the eyes of the user. */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getLocalAddrOfSocket(oslSocket pSocket) +{ + socklen_t AddrLen; + struct sockaddr Addr; + oslSocketAddr pAddr; + + if (pSocket == NULL) /* ENOTSOCK */ + return ((oslSocketAddr)NULL); + + AddrLen= sizeof(struct sockaddr); + + if (getsockname(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR) + return ((oslSocketAddr)NULL); + + pAddr = __osl_createSocketAddrFromSystem( &Addr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_getPeerAddrOfSocket */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getPeerAddrOfSocket(oslSocket pSocket) +{ + socklen_t AddrLen; + struct sockaddr Addr; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return 0; + } + + pSocket->m_nLastError=0; + AddrLen= sizeof(struct sockaddr); + + if(getpeername(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return 0; + } + return __osl_createSocketAddrFromSystem( &Addr ); +} + +/*****************************************************************************/ +/* osl_bindAddrToSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_bindAddrToSocket(oslSocket pSocket, + oslSocketAddr pAddr) +{ + int nRet; + + OSL_ASSERT(pSocket && pAddr ); + if ( pSocket == 0 || pAddr == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = bind(pSocket->m_Socket, &(pAddr->m_sockaddr), sizeof(struct sockaddr)); + + if ( nRet == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + + +/*****************************************************************************/ +/* osl_listenOnSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_listenOnSocket(oslSocket pSocket, + sal_Int32 MaxPendingConnections) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = listen(pSocket->m_Socket, + MaxPendingConnections == -1 ? + SOMAXCONN : + MaxPendingConnections); + if ( nRet == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + + +/*****************************************************************************/ +/* osl_connectSocketTo */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_connectSocketTo(oslSocket pSocket, + oslSocketAddr pAddr, + const TimeValue* pTimeout) +{ + fd_set WriteSet; + fd_set ExcptSet; + int ReadyHandles; + struct timeval tv; + oslSocketResult Result= osl_Socket_Ok; + + OSL_PRECOND(pSocket, "osl_connectSocketTo(): need a valid socket!\n"); + + if ( pSocket == 0 ) + { + return osl_Socket_Error; + } + + pSocket->m_nLastError=0; + + if (osl_isNonBlockingMode(pSocket)) + { + if (connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) != OSL_SOCKET_ERROR) + return osl_Socket_Ok; + else + if (errno == EWOULDBLOCK || errno == EINPROGRESS) + { + pSocket->m_nLastError=EINPROGRESS; + return osl_Socket_InProgress; + } + + + pSocket->m_nLastError=errno; + OSL_TRACE("can't connect : '%s'",strerror(errno)); + return osl_Socket_Error; + } + + /* set socket temporarily to non-blocking */ + OSL_VERIFY(osl_enableNonBlockingMode(pSocket, sal_True)); + + /* initiate connect */ + if(connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) != OSL_SOCKET_ERROR) + { + /* immediate connection */ + osl_enableNonBlockingMode(pSocket, sal_False); + + return osl_Socket_Ok; + } + else + { + /* really an error or just delayed? */ + if (errno != EINPROGRESS) + { + pSocket->m_nLastError=errno; + OSL_TRACE( + "osl_connectSocketTo(): connect failed: errno: %d (%s)\n", + errno, strerror(errno)); + + osl_enableNonBlockingMode(pSocket, sal_False); + return osl_Socket_Error; + } + } + + + /* prepare select set for socket */ + FD_ZERO(&WriteSet); + FD_ZERO(&ExcptSet); + FD_SET(pSocket->m_Socket, &WriteSet); + FD_SET(pSocket->m_Socket, &ExcptSet); + + /* prepare timeout */ + if (pTimeout) + { + /* divide milliseconds into seconds and microseconds */ + tv.tv_sec= pTimeout->Seconds; + tv.tv_usec= pTimeout->Nanosec / 1000L; + } + + /* select */ + ReadyHandles= select(pSocket->m_Socket+1, + 0, + PTR_FD_SET(WriteSet), + PTR_FD_SET(ExcptSet), + (pTimeout) ? &tv : 0); + + if (ReadyHandles > 0) /* connected */ + { + if ( FD_ISSET(pSocket->m_Socket, &WriteSet ) ) + { + int nErrorCode = 0; + socklen_t nErrorSize = sizeof( nErrorCode ); + + int nSockOpt; + + nSockOpt = getsockopt ( pSocket->m_Socket, SOL_SOCKET, SO_ERROR, + &nErrorCode, &nErrorSize ); + if ( (nSockOpt == 0) && (nErrorCode == 0)) + Result = osl_Socket_Ok; + else + Result = osl_Socket_Error; + } + else + { + Result= osl_Socket_Error; + } + } + else if (ReadyHandles < 0) /* error */ + { + if (errno == EBADF) /* most probably interrupted by close() */ + { + /* do not access pSockImpl because it is about to be or */ + /* already destroyed */ + return osl_Socket_Interrupted; + } + else + { + pSocket->m_nLastError=errno; + Result= osl_Socket_Error; + } + } + else /* timeout */ + { + pSocket->m_nLastError=errno; + Result= osl_Socket_TimedOut; + } + + osl_enableNonBlockingMode(pSocket, sal_False); + + return Result; +} + + +/*****************************************************************************/ +/* osl_acceptConnectionOnSocket */ +/*****************************************************************************/ +oslSocket SAL_CALL osl_acceptConnectionOnSocket(oslSocket pSocket, + oslSocketAddr* ppAddr) +{ + struct sockaddr Addr; + int Connection, Flags; + oslSocket pConnectionSockImpl; + + socklen_t AddrLen = sizeof(struct sockaddr); + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return 0; + } + + pSocket->m_nLastError=0; +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_True; +#endif /* LINUX */ + + if( ppAddr && *ppAddr ) + { + osl_destroySocketAddr( *ppAddr ); + *ppAddr = 0; + } + + /* prevent Linux EINTR behaviour */ + do + { + Connection = accept(pSocket->m_Socket, &Addr, &AddrLen); + } while (Connection == -1 && errno == EINTR); + + + /* accept failed? */ + if( Connection == OSL_SOCKET_ERROR ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_acceptConnectionOnSocket : accept error '%s'\n",strerror(errno)); + +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_False; +#endif /* LINUX */ + return 0; + } + + OSL_ASSERT(AddrLen == sizeof(struct sockaddr)); + + +#if defined(LINUX) + if ( pSocket->m_bIsInShutdown == sal_True ) + { + close(Connection); + OSL_TRACE("osl_acceptConnectionOnSocket : close while accept\n"); + return 0; + } +#endif /* LINUX */ + + + if(ppAddr) + { + *ppAddr= __osl_createSocketAddrFromSystem(&Addr); + } + + /* alloc memory */ + pConnectionSockImpl= __osl_createSocketImpl(OSL_INVALID_SOCKET); + + /* set close-on-exec flag */ + if ((Flags = fcntl(Connection, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + if (fcntl(Connection, F_SETFD, Flags) == -1) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_acceptConnectionOnSocket failed changing socket flags. Errno: %d (%s)\n", + errno, + strerror(errno)); + } + + } + + pConnectionSockImpl->m_Socket = Connection; + pConnectionSockImpl->m_nLastError = 0; + pConnectionSockImpl->m_CloseCallback = NULL; + pConnectionSockImpl->m_CallbackArg = NULL; +#if defined(LINUX) + pConnectionSockImpl->m_bIsAccepting = sal_False; + + pSocket->m_bIsAccepting = sal_False; +#endif /* LINUX */ + return pConnectionSockImpl; +} + +/*****************************************************************************/ +/* osl_receiveSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receiveSocket(oslSocket pSocket, + void* pBuffer, + sal_uInt32 BytesToRead, + oslSocketMsgFlag Flag) +{ + int nRead; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_receiveSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + do + { + nRead = recv(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToRead, + MSG_FLAG_TO_NATIVE(Flag)); + } while ( nRead < 0 && errno == EINTR ); + + if ( nRead < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,strerror(errno)); + } + else if ( nRead == 0 ) + { + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,"EOL"); + } + + return nRead; +} + + +/*****************************************************************************/ +/* osl_receiveFromSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receiveFromSocket(oslSocket pSocket, + oslSocketAddr pSenderAddr, + void* pBuffer, + sal_uInt32 BufferSize, + oslSocketMsgFlag Flag) +{ + int nRead; + struct sockaddr *pSystemSockAddr = 0; + socklen_t AddrLen = 0; + if( pSenderAddr ) + { + AddrLen = sizeof( struct sockaddr ); + pSystemSockAddr = &(pSenderAddr->m_sockaddr); + } + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_receiveFromSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + nRead = recvfrom(pSocket->m_Socket, + (sal_Char*)pBuffer, + BufferSize, + MSG_FLAG_TO_NATIVE(Flag), + pSystemSockAddr, + &AddrLen); + + if ( nRead < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_receiveFromSocket failed : %i '%s'",nRead,strerror(errno)); + } + else if ( nRead == 0 ) + { + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,"EOL"); + } + + return nRead; +} + + +/*****************************************************************************/ +/* osl_sendSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendSocket(oslSocket pSocket, + const void* pBuffer, + sal_uInt32 BytesToSend, + oslSocketMsgFlag Flag) +{ + int nWritten; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_sendSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + do + { + nWritten = send(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, + MSG_FLAG_TO_NATIVE(Flag)); + } while ( nWritten < 0 && errno == EINTR ); + + + if ( nWritten < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_sendSocket failed : %i '%s'",nWritten,strerror(errno)); + } + else if ( nWritten == 0 ) + { + OSL_TRACE("osl_sendSocket failed : %i '%s'",nWritten,"EOL"); + } + + return nWritten; +} + +/*****************************************************************************/ +/* osl_sendToSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendToSocket(oslSocket pSocket, + oslSocketAddr ReceiverAddr, + const void* pBuffer, + sal_uInt32 BytesToSend, + oslSocketMsgFlag Flag) +{ + int nWritten; + + struct sockaddr *pSystemSockAddr = 0; + int AddrLen = 0; + if( ReceiverAddr ) + { + pSystemSockAddr = &(ReceiverAddr->m_sockaddr); + AddrLen = sizeof( struct sockaddr ); + } + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_sendToSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + /* ReceiverAddr might be 0 when used on a connected socket. */ + /* Then sendto should behave like send. */ + + nWritten = sendto(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, + MSG_FLAG_TO_NATIVE(Flag), + pSystemSockAddr, + AddrLen); + + if ( nWritten < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_sendToSocket failed : %i '%s'",nWritten,strerror(errno)); + } + else if ( nWritten == 0 ) + { + OSL_TRACE("osl_sendToSocket failed : %i '%s'",nWritten,"EOL"); + } + + return nWritten; +} + +/*****************************************************************************/ +/* osl_readSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_readSocket ( + oslSocket pSocket, void *pBuffer, sal_Int32 n ) +{ + sal_uInt8 * Ptr = (sal_uInt8 *)pBuffer; + sal_uInt32 BytesRead= 0; + sal_uInt32 BytesToRead= n; + + OSL_ASSERT( pSocket); + + /* loop until all desired bytes were read or an error occured */ + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receiveSocket(pSocket, + Ptr, + BytesToRead, + osl_Socket_MsgNormal); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToRead -= RetVal; + BytesRead += RetVal; + Ptr += RetVal; + } + + return BytesRead; +} + +/*****************************************************************************/ +/* osl_writeSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_writeSocket( + oslSocket pSocket, const void *pBuffer, sal_Int32 n ) +{ + /* loop until all desired bytes were send or an error occured */ + sal_uInt32 BytesSend= 0; + sal_uInt32 BytesToSend= n; + sal_uInt8 *Ptr = ( sal_uInt8 * )pBuffer; + + OSL_ASSERT( pSocket ); + + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendSocket( pSocket,Ptr,BytesToSend,osl_Socket_MsgNormal); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToSend -= RetVal; + BytesSend += RetVal; + Ptr += RetVal; + + } + return BytesSend; +} + +/*****************************************************************************/ +/* __osl_socket_poll */ +/*****************************************************************************/ + +#ifdef HAVE_POLL_H /* poll() */ + +sal_Bool __osl_socket_poll ( + oslSocket pSocket, + const TimeValue* pTimeout, + short nEvent) +{ + struct pollfd fds; + int timeout; + int result; + + OSL_ASSERT(pSocket); + pSocket->m_nLastError = 0; + + fds.fd = pSocket->m_Socket; + fds.events = nEvent; + fds.revents = 0; + + timeout = -1; + if (pTimeout) + { + /* Convert to [ms] */ + timeout = pTimeout->Seconds * 1000; + timeout += pTimeout->Nanosec / (1000 * 1000); + } + + result = poll (&fds, 1, timeout); + if (result < 0) + { + pSocket->m_nLastError = errno; + OSL_TRACE("__osl_socket_poll(): poll error: %d (%s)", + errno, strerror(errno)); + return sal_False; + } + if (result == 0) + { + /* Timeout */ + return sal_False; + } + + return ((fds.revents & nEvent) == nEvent); +} + +#else /* select() */ + +sal_Bool __osl_socket_poll ( + oslSocket pSocket, + const TimeValue* pTimeout, + short nEvent) +{ + fd_set fds; + struct timeval tv; + int result; + + OSL_ASSERT(pSocket); + pSocket->m_nLastError = 0; + + FD_ZERO(&fds); + FD_SET(pSocket->m_Socket, &fds); + + if (pTimeout) + { + /* Convert to 'timeval' */ + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000; + } + + result = select ( + pSocket->m_Socket + 1, + (nEvent == POLLIN ) ? PTR_FD_SET(fds) : NULL, + (nEvent == POLLOUT) ? PTR_FD_SET(fds) : NULL, + (nEvent == POLLPRI) ? PTR_FD_SET(fds) : NULL, + (pTimeout) ? &tv : NULL); + + if (result < 0) + { + pSocket->m_nLastError = errno; + OSL_TRACE("__osl_socket_poll(): select error: %d (%s)", + errno, strerror(errno)); + return sal_False; + } + if (result == 0) + { + /* Timeout */ + return sal_False; + } + + return (FD_ISSET(pSocket->m_Socket, &fds) ? sal_True : sal_False); +} + +#endif /* HAVE_POLL_H */ + +/*****************************************************************************/ +/* osl_isReceiveReady */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isReceiveReady ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLIN); +} + +/*****************************************************************************/ +/* osl_isSendReady */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isSendReady ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLOUT); +} + +/*****************************************************************************/ +/* osl_isExceptionPending */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isExceptionPending ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLPRI); +} + +/*****************************************************************************/ +/* osl_shutdownSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_shutdownSocket(oslSocket pSocket, + oslSocketDirection Direction) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet=shutdown(pSocket->m_Socket, DIRECTION_TO_NATIVE(Direction)); + if (nRet != 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("shutdown error '%s'\n",strerror(errno)); + } + return (nRet==0); +} + + +/*****************************************************************************/ +/* osl_getSocketOption */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getSocketOption(oslSocket pSocket, + oslSocketOptionLevel Level, + oslSocketOption Option, + void* pBuffer, + sal_uInt32 BufferLen) +{ + socklen_t nOptLen = (socklen_t) BufferLen; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return -1; + } + + pSocket->m_nLastError=0; + + if(getsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(Level), + OPTION_TO_NATIVE(Option), + (sal_Char*)pBuffer, + &nOptLen) == -1) + { + pSocket->m_nLastError=errno; + return -1; + } + + return BufferLen; +} + +/*****************************************************************************/ +/* osl_setSocketOption */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setSocketOption(oslSocket pSocket, + oslSocketOptionLevel Level, + oslSocketOption Option, + void* pBuffer, + sal_uInt32 BufferLen) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = setsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(Level), + OPTION_TO_NATIVE(Option), + (sal_Char*)pBuffer, + BufferLen); + + if ( nRet < 0 ) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + +/*****************************************************************************/ +/* osl_enableNonBlockingMode */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_enableNonBlockingMode(oslSocket pSocket, + sal_Bool On) +{ + int flags; + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + flags = fcntl(pSocket->m_Socket, F_GETFL, 0); + + if (On) + flags |= O_NONBLOCK; + else + flags &= ~(O_NONBLOCK); + + nRet = fcntl(pSocket->m_Socket, F_SETFL, flags); + + if ( nRet < 0 ) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + +/*****************************************************************************/ +/* osl_isNonBlockingMode */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isNonBlockingMode(oslSocket pSocket) +{ + int flags; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + flags = fcntl(pSocket->m_Socket, F_GETFL, 0); + + if (flags == -1 || !(flags & O_NONBLOCK)) + return sal_False; + else + return sal_True; +} + +/*****************************************************************************/ +/* osl_getSocketType */ +/*****************************************************************************/ +oslSocketType SAL_CALL osl_getSocketType(oslSocket pSocket) +{ + int Type=0; + socklen_t TypeSize= sizeof(Type); + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return osl_Socket_TypeInvalid; + } + + pSocket->m_nLastError=0; + + if(getsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(osl_Socket_LevelSocket), + OPTION_TO_NATIVE(osl_Socket_OptionType), + (sal_Char*)&Type, + &TypeSize) == -1) + { + /* error */ + pSocket->m_nLastError=errno; + return osl_Socket_TypeInvalid; + } + + return TYPE_FROM_NATIVE(Type); + +} + +/*****************************************************************************/ +/* osl_getLastSocketErrorDescription */ +/*****************************************************************************/ +void SAL_CALL osl_getLastSocketErrorDescription(oslSocket Socket, rtl_uString **ustrError) +{ + sal_Char pszError[1024]; + + pszError[0] = '\0'; + + osl_psz_getLastSocketErrorDescription(Socket,pszError,sizeof(pszError)); + + rtl_uString_newFromAscii(ustrError,pszError); + + return; +} + + +void SAL_CALL osl_psz_getLastSocketErrorDescription(oslSocket pSocket, sal_Char* pBuffer, sal_uInt32 BufferSize) +{ + /* make shure pBuffer will be a zero-terminated string even when strncpy has to cut */ + pBuffer[BufferSize-1]= '\0'; + + if ( pSocket == 0 ) + { + strncpy(pBuffer, strerror(EINVAL), BufferSize-1); + return; + } + + strncpy(pBuffer, strerror(pSocket->m_nLastError), BufferSize-1); + return; +} + +/*****************************************************************************/ +/* osl_getLastSocketError */ +/*****************************************************************************/ +oslSocketError SAL_CALL osl_getLastSocketError(oslSocket pSocket) +{ + if ( pSocket == 0 ) + { + return ERROR_FROM_NATIVE(EINVAL); + } + + return ERROR_FROM_NATIVE(pSocket->m_nLastError); +} + +/*****************************************************************************/ +/* SocketSet */ +/*****************************************************************************/ +typedef struct _TSocketSetImpl +{ + int m_MaxHandle; /* for select(), the largest descriptor in the set */ + fd_set m_Set; /* the set of descriptors */ + +} TSocketSetImpl; + +/*****************************************************************************/ +/* osl_createSocketSet */ +/*****************************************************************************/ +oslSocketSet SAL_CALL osl_createSocketSet() +{ + TSocketSetImpl* pSet; + + pSet= (TSocketSetImpl*)malloc(sizeof(TSocketSetImpl)); + + OSL_ASSERT(pSet); + + if(pSet) + { + pSet->m_MaxHandle= 0; + FD_ZERO(&pSet->m_Set); + } + + return (oslSocketSet)pSet; +} + +/*****************************************************************************/ +/* osl_destroySocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_destroySocketSet(oslSocketSet Set) +{ + if(Set) + free(Set); +} + +/*****************************************************************************/ +/* osl_clearSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_clearSocketSet(oslSocketSet Set) +{ + TSocketSetImpl* pSet; + OSL_ASSERT(Set); + if ( Set == 0 ) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + pSet->m_MaxHandle= 0; + + FD_ZERO(&pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_addToSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_addToSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + + if ( Set == 0 || pSocket == 0) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + + /* correct max handle */ + if(pSocket->m_Socket > pSet->m_MaxHandle) + pSet->m_MaxHandle= pSocket->m_Socket; + FD_SET(pSocket->m_Socket, &pSet->m_Set); + +} + +/*****************************************************************************/ +/* osl_removeFromSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_removeFromSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + + if ( Set == 0 || pSocket == 0) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + + /* correct max handle */ + if(pSocket->m_Socket == pSet->m_MaxHandle) + { + /* not optimal, since the next used descriptor might be */ + /* much smaller than m_Socket-1, but it will do */ + pSet->m_MaxHandle--; + if(pSet->m_MaxHandle < 0) + { + pSet->m_MaxHandle= 0; /* avoid underflow */ + } + } + + FD_CLR(pSocket->m_Socket, &pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_isInSocketSet */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isInSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + if ( Set == 0 || pSocket == 0 ) + { + return sal_False; + } + + pSet= (TSocketSetImpl*)Set; + + return (FD_ISSET(pSocket->m_Socket, &pSet->m_Set) != 0); +} + +/*****************************************************************************/ +/* osl_demultiplexSocketEvents */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_demultiplexSocketEvents(oslSocketSet IncomingSet, + oslSocketSet OutgoingSet, + oslSocketSet OutOfBandSet, + const TimeValue* pTimeout) +{ + int MaxHandle= 0; + struct timeval tv; + TSocketSetImpl* pInSet; + TSocketSetImpl* pOutSet; + TSocketSetImpl* pOOBSet; + + if (pTimeout) + { + /* non-blocking call */ + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000L; + } + + /* map opaque data to impl-types */ + pInSet= (TSocketSetImpl*)IncomingSet; + pOutSet= (TSocketSetImpl*)OutgoingSet; + pOOBSet= (TSocketSetImpl*)OutOfBandSet; + + /* get max handle from all sets */ + if (pInSet) + MaxHandle= pInSet->m_MaxHandle; + + if (pOutSet && (pOutSet->m_MaxHandle > MaxHandle)) + MaxHandle= pOutSet->m_MaxHandle; + + if (pOOBSet && (pOOBSet->m_MaxHandle > MaxHandle)) + MaxHandle= pOOBSet->m_MaxHandle; + + return select(MaxHandle+1, + pInSet ? PTR_FD_SET(pInSet->m_Set) : 0, + pOutSet ? PTR_FD_SET(pOutSet->m_Set) : 0, + pOOBSet ? PTR_FD_SET(pOOBSet->m_Set) : 0, + pTimeout ? &tv : 0); +} + diff --git a/sal/osl/unx/sockimpl.h b/sal/osl/unx/sockimpl.h new file mode 100644 index 000000000000..86122e850875 --- /dev/null +++ b/sal/osl/unx/sockimpl.h @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_SOCKETIMPL_H_ +#define _OSL_SOCKETIMPL_H_ + +#include <osl/pipe.h> +#include <osl/socket.h> +#include <osl/interlck.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (*oslCloseCallback) (void*); + +struct oslSocketImpl { + int m_Socket; + int m_nLastError; + oslCloseCallback m_CloseCallback; + void* m_CallbackArg; + oslInterlockedCount m_nRefCount; +#if defined(LINUX) + sal_Bool m_bIsAccepting; + sal_Bool m_bIsInShutdown; +#endif +}; + +struct oslSocketAddrImpl +{ + sal_Int32 m_nRefCount; + struct sockaddr m_sockaddr; +}; + +struct oslPipeImpl { + int m_Socket; + sal_Char m_Name[PATH_MAX + 1]; + oslInterlockedCount m_nRefCount; + sal_Bool m_bClosed; +#if defined(LINUX) + sal_Bool m_bIsAccepting; + sal_Bool m_bIsInShutdown; +#endif +}; + +oslSocket __osl_createSocketImpl(int Socket); +void __osl_destroySocketImpl(oslSocket pImpl); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/unx/system.c b/sal/osl/unx/system.c new file mode 100644 index 000000000000..0ea3b819438c --- /dev/null +++ b/sal/osl/unx/system.c @@ -0,0 +1,599 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#ifdef NO_PTHREAD_RTL + +static pthread_mutex_t getrtl_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* struct passwd differs on some platforms */ +#if defined NETBSD +struct passwd *getpwnam_r(const char* name, struct passwd* s, char* buffer, int size ) +{ + struct passwd* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = getpwnam(name)) ) + { + int nname, npasswd, nclass, ngecos, ndir; + + nname= strlen(res->pw_name)+1; + npasswd= strlen(res->pw_passwd)+1; + nclass= strlen(res->pw_class)+1; + ngecos= strlen(res->pw_gecos)+1; + ndir= strlen(res->pw_dir)+1; + + if (nname+npasswd+nclass+ngecos + +ndir+strlen(res->pw_shell) < size) + { + memcpy(s, res, sizeof(struct passwd)); + + strcpy(buffer, res->pw_name); + s->pw_name = buffer; + buffer += nname; + + strcpy(buffer, res->pw_passwd); + s->pw_passwd = buffer; + buffer += npasswd; + + strcpy(buffer, res->pw_class); + s->pw_class = buffer; + buffer += nclass; + + strcpy(buffer, res->pw_gecos); + s->pw_gecos = buffer; + buffer += ngecos; + + strcpy(buffer, res->pw_dir); + s->pw_dir = buffer; + buffer += ndir; + + strcpy(buffer, res->pw_shell); + s->pw_shell = buffer; + + res = s; + } + else + res = 0; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return(res); +} + +int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, + size_t buflen, struct passwd **result) +{ + struct passwd* res; + int retval = 0; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = getpwuid(uid)) ) + { + size_t pw_name, pw_passwd, pw_class, pw_gecos, pw_dir, pw_shell; + + pw_name = strlen(res->pw_name)+1; + pw_passwd = strlen(res->pw_passwd)+1; + pw_class = strlen(res->pw_class)+1; + pw_gecos = strlen(res->pw_gecos)+1; + pw_dir = strlen(res->pw_dir)+1; + pw_shell = strlen(res->pw_shell)+1; + + if (pw_name+pw_passwd+pw_class+pw_gecos + +pw_dir+pw_shell < buflen) + { + memcpy(pwd, res, sizeof(struct passwd)); + + strncpy(buffer, res->pw_name, pw_name); + pwd->pw_name = buffer; + buffer += pw_name; + + strncpy(buffer, res->pw_passwd, pw_passwd); + pwd->pw_passwd = buffer; + buffer += pw_passwd; + + strncpy(buffer, res->pw_class, pw_class); + pwd->pw_class = buffer; + buffer += pw_class; + + strncpy(buffer, res->pw_gecos, pw_gecos); + pwd->pw_gecos = buffer; + buffer += pw_gecos; + + strncpy(buffer, res->pw_dir, pw_dir); + pwd->pw_dir = buffer; + buffer += pw_dir; + + strncpy(buffer, res->pw_shell, pw_shell); + pwd->pw_shell = buffer; + buffer += pw_shell; + + *result = pwd ; + retval = 0 ; + + } + else + retval = ENOMEM; + } + else + retval = errno ; + + pthread_mutex_unlock(&getrtl_mutex); + + return retval; +} + +struct tm *localtime_r(const time_t *timep, struct tm *buffer) +{ + struct tm* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = localtime(timep))) + { + memcpy(buffer, res, sizeof(struct tm)); + res = buffer; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} + +struct tm *gmtime_r(const time_t *timep, struct tm *buffer) +{ + struct tm* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = gmtime(timep)) ) + { + memcpy(buffer, res, sizeof(struct tm)); + res = buffer; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} +#endif /* defined NETBSD */ + +#ifdef SCO +#include <pwd.h> +#include <shadow.h> +#include <sys/types.h> + +struct spwd *getspnam_r(const char *name, struct spwd* s, char* buffer, int size ) +{ + struct spwd* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( res = getspnam(name) ) + { + int nnamp; + + nnamp = strlen(res->sp_namp)+1; + + if (nnamp+strlen(res->sp_pwdp) < size) { + memcpy(s, res, sizeof(struct spwd)); + + strcpy(buffer, res->sp_namp); + s->sp_namp = buffer; + buffer += nnamp; + + strcpy(buffer, res->sp_pwdp); + s->sp_pwdp = buffer; + + res = s; + } + else + res = 0; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} + +struct passwd *getpwnam_r(const char* name, struct passwd* s, char* buffer, int size ) +{ + struct passwd* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( res = getpwnam(name) ) + { + int nname, npasswd, nage; + int ncomment, ngecos, ndir; + + nname= strlen(res->pw_name)+1; + npasswd= strlen(res->pw_passwd)+1; + nage= strlen(res->pw_age)+1; + ncomment= strlen(res->pw_comment)+1; + ngecos= strlen(res->pw_gecos)+1; + ndir= strlen(res->pw_dir)+1; + + if (nname+npasswd+nage+ncomment+ngecos+ndir + +strlen(res->pw_shell) < size) + { + memcpy(s, res, sizeof(struct passwd)); + + strcpy(buffer, res->pw_name); + s->pw_name = buffer; + buffer += nname; + + strcpy(buffer, res->pw_passwd); + s->pw_passwd = buffer; + buffer += npasswd; + + strcpy(buffer, res->pw_age); + s->pw_age = buffer; + buffer += nage; + + strcpy(buffer, res->pw_comment); + s->pw_comment = buffer; + buffer += ncomment; + + strcpy(buffer, res->pw_gecos); + s->pw_gecos = buffer; + buffer += ngecos; + + strcpy(buffer, res->pw_dir); + s->pw_dir = buffer; + buffer += ndir; + + strcpy(buffer, res->pw_shell); + s->pw_shell = buffer; + + res = s; + } + else + res = 0; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} +#endif /* defined SCO */ + +#if !defined(FREEBSD) || (__FreeBSD_version < 601103) + +extern int h_errno; + +struct hostent *gethostbyname_r(const char *name, struct hostent *result, + char *buffer, int buflen, int *h_errnop) +{ + /* buffer layout: name\0 + * array_of_pointer_to_aliases + * NULL + * alias1\0...aliasn\0 + * array_of_pointer_to_addresses + * NULL + * addr1addr2addr3...addrn + */ + struct hostent* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = gethostbyname(name)) ) + { + int nname, naliases, naddr_list, naliasesdata, n; + char **p, **parray, *data; + + /* Check buffer size before copying, we want to leave the + * buffers unmodified in case something goes wrong. + * + * Is this required? + */ + + nname= strlen(res->h_name)+1; + + naliases = naddr_list = naliasesdata = 0; + + for ( p = res->h_aliases; *p != NULL; p++) { + naliases++; + naliasesdata += strlen(*p)+1; + } + + for ( p = res->h_addr_list; *p != NULL; p++) + naddr_list++; + + if ( nname + + (naliases+1)*sizeof(char*) + naliasesdata + + (naddr_list+1)*sizeof(char*) + naddr_list*res->h_length + <= buflen ) + { + memcpy(result, res, sizeof(struct hostent)); + + strcpy(buffer, res->h_name); + result->h_name = buffer; + buffer += nname; + + parray = (char**)buffer; + result->h_aliases = parray; + data = buffer + (naliases+1)*sizeof(char*); + for ( p = res->h_aliases; *p != NULL; p++) { + n = strlen(*p)+1; + *parray++ = data; + memcpy(data, *p, n); + data += n; + } + *parray = NULL; + buffer = data; + parray = (char**)buffer; + result->h_addr_list = parray; + data = buffer + (naddr_list+1)*sizeof(char*); + for ( p = res->h_addr_list; *p != NULL; p++) { + *parray++ = data; + memcpy(data, *p, res->h_length); + data += res->h_length; + } + *parray = NULL; + + res = result; + } + else + { + errno = ERANGE; + res = NULL; + } + } + else + { + *h_errnop = h_errno; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} +#endif /* !defined(FREEBSD) || (__FreeBSD_version < 601103) */ + +#if defined(MACOSX) +/* + * Add support for resolving Mac native alias files (not the same as unix alias files) + * returns 0 on success. + */ +int macxp_resolveAlias(char *path, int buflen) +{ + FSRef aFSRef; + OSStatus nErr; + Boolean bFolder; + Boolean bAliased; + char *unprocessedPath = path; + + if ( *unprocessedPath == '/' ) + unprocessedPath++; + + int nRet = 0; + while ( !nRet && unprocessedPath && *unprocessedPath ) + { + unprocessedPath = strchr( unprocessedPath, '/' ); + if ( unprocessedPath ) + *unprocessedPath = '\0'; + + nErr = noErr; + bFolder = FALSE; + bAliased = FALSE; + if ( FSPathMakeRef( (const UInt8 *)path, &aFSRef, 0 ) == noErr ) + { + nErr = FSResolveAliasFileWithMountFlags( &aFSRef, TRUE, &bFolder, &bAliased, kResolveAliasFileNoUI ); + if ( nErr == nsvErr ) + { + errno = ENOENT; + nRet = -1; + } + else if ( nErr == noErr && bAliased ) + { + char tmpPath[ PATH_MAX ]; + if ( FSRefMakePath( &aFSRef, (UInt8 *)tmpPath, PATH_MAX ) == noErr ) + { + int nLen = strlen( tmpPath ) + ( unprocessedPath ? strlen( unprocessedPath + 1 ) + 1 : 0 ); + if ( nLen < buflen && nLen < PATH_MAX ) + { + if ( unprocessedPath ) + { + int nTmpPathLen = strlen( tmpPath ); + strcat( tmpPath, "/" ); + strcat( tmpPath, unprocessedPath + 1 ); + strcpy( path, tmpPath); + unprocessedPath = path + nTmpPathLen; + } + else if ( !unprocessedPath ) + { + strcpy( path, tmpPath); + } + } + else + { + errno = ENAMETOOLONG; + nRet = -1; + } + } + } + } + + if ( unprocessedPath ) + *unprocessedPath++ = '/'; + } + + return nRet; +} + +#endif /* defined MACOSX */ + +#endif /* NO_PTHREAD_RTL */ + +#if (defined (LINUX) && (GLIBC >= 2)) +/* The linux kernel thread implemention, always return the pid of the + thread subprocess and not of the main process. So we save the main + pid at startup +*/ + +// Directly from libc.so.6, obviously missing from some unistd.h: +extern __pid_t __getpid(void); + +static pid_t pid = -1; + +static void savePid(void) __attribute__((constructor)); + +static void savePid(void) +{ + if (pid == -1) + pid = __getpid(); +} + +pid_t getpid(void) +{ + if (pid == -1) + savePid(); + + return (pid); +} +#endif /* (defined (LINUX) && (GLIBC >= 2)) */ + +#ifdef NO_PTHREAD_SEMAPHORES +int sem_init(sem_t* sem, int pshared, unsigned int value) +{ + pthread_mutex_init(&sem->mutex, PTHREAD_MUTEXATTR_DEFAULT); + pthread_cond_init(&sem->increased, PTHREAD_CONDATTR_DEFAULT); + + sem->value = (int)value; + return 0; +} + +int sem_destroy(sem_t* sem) +{ + pthread_mutex_destroy(&sem->mutex); + pthread_cond_destroy(&sem->increased); + sem->value = 0; + return 0; +} + +int sem_wait(sem_t* sem) +{ + pthread_mutex_lock(&sem->mutex); + + while (sem->value <= 0) + { + pthread_cond_wait(&sem->increased, &sem->mutex); + } + + sem->value--; + pthread_mutex_unlock(&sem->mutex); + + return 0; +} + +int sem_trywait(sem_t* sem) +{ + int result = 0; + + pthread_mutex_lock(&sem->mutex); + + if (sem->value > 0) + { + sem->value--; + } + else + { + errno = EAGAIN; + result = -1; + } + + pthread_mutex_unlock(&sem->mutex); + + return result; +} + +int sem_post(sem_t* sem) +{ + pthread_mutex_lock(&sem->mutex); + + sem->value++; + + pthread_mutex_unlock(&sem->mutex); + + pthread_cond_signal(&sem->increased); + + return 0; +} +#endif + +#if defined(FREEBSD) +char *fcvt(double value, int ndigit, int *decpt, int *sign) +{ + static char ret[256]; + char buf[256],zahl[256],format[256]="%"; + char *v1,*v2; + + if (value==0.0) value=1e-30; + + if (value<0.0) *sign=1; else *sign=0; + + if (value<1.0) + { + *decpt=(int)log10(value); + value*=pow(10.0,1-*decpt); + ndigit+=*decpt-1; + if (ndigit<0) ndigit=0; + } + else + { + *decpt=(int)log10(value)+1; + } + + sprintf(zahl,"%d",ndigit); + strcat(format,zahl); + strcat(format,"."); + strcat(format,zahl); + strcat(format,"f"); + + sprintf(buf,format,value); + + if (ndigit!=0) + { + v1=strtok(buf,"."); + v2=strtok(NULL,"."); + strcpy(ret,v1); + strcat(ret,v2); + } + else + { + strcpy(ret,buf); + } + + return(ret); +} + +#endif diff --git a/sal/osl/unx/system.h b/sal/osl/unx/system.h new file mode 100644 index 000000000000..1cb0979490c0 --- /dev/null +++ b/sal/osl/unx/system.h @@ -0,0 +1,495 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __OSL_SYSTEM_H__ +#define __OSL_SYSTEM_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> + +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <signal.h> +#include <utime.h> + +#include <pwd.h> + +#include <netdb.h> + +#include <sys/stat.h> +#include <sys/wait.h> + +#include <sys/types.h> + +/* Make sockets of type AF_UNIX use underlying FS rights */ +#ifdef SOLARIS +# define _XOPEN_SOURCE 500 +# include <sys/socket.h> +# undef _XOPEN_SOURCE +#else +# include <sys/socket.h> +#endif + +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifdef SYSV +# include <sys/utsname.h> +#endif + +#ifdef LINUX +# ifndef __USE_GNU +# define __USE_GNU +# endif + +#if GLIBC >= 2 +# include <shadow.h> +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <sys/uio.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <dlfcn.h> +# include <endian.h> +# include <sys/time.h> +# include <semaphore.h> +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif __BYTE_ORDER == __BIG_ENDIAN +# ifndef _BIG_ENDIAN +# define _BIG_ENDIAN +# endif +# elif __BYTE_ORDER == __PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_PRIORITY +# define PTHREAD_SIGACTION pthread_sigaction +#else +# include <shadow.h> +# include <asm/sigcontext.h> +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <linux/net.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <linux/elfcore.h> +# include <dlfcn.h> +# include <endian.h> +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif __BYTE_ORDER == __BIG_ENDIAN +# define _BIG_ENDIAN +# elif __BYTE_ORDER == __PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_RTL +# define NO_PTHREAD_PRIORITY +# define PTHREAD_SIGACTION pthread_sigaction +#endif + +# ifndef ETIME +# define ETIME ETIMEDOUT +# endif + +#endif + +#ifdef NETBSD +# define ETIME ETIMEDOUT +# define _POSIX_THREAD_SYSCALL_SOFT 1 +# include <pthread.h> +# include <netdb.h> +# include <sys/sem.h> +# include <sys/exec.h> +# include <sys/filio.h> +# include <sys/ioctl.h> +# include <sys/time.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <dlfcn.h> +# include <machine/endian.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN_OO +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN_OO +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN_OO +# endif +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_PRIORITY +# define NO_PTHREAD_SEMAPHORES +# define NO_PTHREAD_RTL +# define PTHREAD_SIGACTION pthread_sigaction +#endif + +#ifdef FREEBSD +# define ETIME ETIMEDOUT +# include <pthread.h> +# include <sys/sem.h> +# include <semaphore.h> +# include <dlfcn.h> +# include <sys/filio.h> +# include <sys/ioctl.h> +# include <sys/param.h> +# include <sys/time.h> +# include <sys/uio.h> +# include <sys/exec.h> +# include <vm/vm.h> +# include <vm/vm_param.h> +# include <vm/pmap.h> +# include <vm/swap_pager.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# define IORESOURCE_TRANSFER_BSD +# include <machine/endian.h> +#if __FreeBSD_version < 500000 +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +#endif +# define NO_PTHREAD_RTL +#endif + +#ifdef SCO +# define AF_IPX -1 +# include <strings.h> +# include <pthread.h> +# include <shadow.h> +# include <netdb.h> +# include <sys/un.h> +# include <sys/netinet/tcp.h> +# include <sys/types.h> +# include <sys/byteorder.h> +# include <dlfcn.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define sched_yield() pthread_yield() +# define pthread_testcancel() +# define NO_PTHREAD_RTL +# define NO_PTHREAD_PRIORITY +extern int pthread_cancel(pthread_t); +extern unsigned int nanosleep(unsigned int); +# define SLEEP_TIMESPEC(timespec) (timespec .tv_sec > 0) ? sleep(timespec .tv_sec), nanosleep(timespec .tv_nsec) : nanosleep(timespec .tv_nsec) +# define PATH_MAX _POSIX_PATH_MAX +# define S_ISSOCK S_ISFIFO +# define PTHREAD_SIGACTION pthread_sigaction +# define STAT_PARENT stat +#endif + +#ifdef AIX +# define AF_IPX -1 +# include <strings.h> +# include <pthread.h> +# include <sys/time.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <sys/machine.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define sched_yield() pthread_yield() +# define SLEEP_TIMESPEC(timespec) nsleep(×pec, 0) +# define LIBPATH "LIBPATH" +# define NO_PTHREAD_SEMAPHORES +# define NO_DL_FUNCTIONS +#endif + +#ifdef HPUX +# define AF_IPX -1 +# undef howmany +# undef MAXINT +# include <pthread.h> +# include <sys/un.h> +# include <sys/sched.h> +# include <sys/xti.h> +# include <sys/pstat.h> +# include <shadow.h> +# include <crypt.h> +# include <machine/param.h> +# define LIBPATH "SHLIB_PATH" +# define PTR_FD_SET(s) ((int *)&(s)) +# define PTHREAD_VALUE(t) ((t).field2) +# define PTHREAD_NONE_INIT { 0, -1 } +# define PTHREAD_ATTR_DEFAULT pthread_attr_default +# define PTHREAD_MUTEXATTR_DEFAULT pthread_mutexattr_default +# define PTHREAD_CONDATTR_DEFAULT pthread_condattr_default +# define pthread_detach(t) pthread_detach(&(t)) +# define NO_PTHREAD_PRIORITY +# define NO_PTHREAD_SEMAPHORES +# define NO_DL_FUNCTIONS +# undef sigaction +# define PTHREAD_SIGACTION cma_sigaction +#endif + +#ifdef SOLARIS +# include <shadow.h> +# include <sys/un.h> +# include <stropts.h> +# include <pthread.h> +# include <semaphore.h> +# include <netinet/tcp.h> +# include <sys/filio.h> +# include <dlfcn.h> +# include <sys/isa_defs.h> +# define IORESOURCE_TRANSFER_SYSV +# define IOCHANNEL_TRANSFER_BSD +# define LIBPATH "LD_LIBRARY_PATH" +#endif + +#ifdef MACOSX +#define __OPENTRANSPORTPROVIDERS__ // these are already defined +#define TimeValue CFTimeValue // Do not conflict with TimeValue in sal/inc/osl/time.h +#include <Carbon/Carbon.h> +#undef TimeValue +# ifndef ETIME +# define ETIME ETIMEDOUT +# endif +# include <dlfcn.h> +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <sys/uio.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <machine/endian.h> +# include <sys/time.h> +# include <sys/semaphore.h> +/* fixme are premac and postmac still needed here? */ +# include <premac.h> +# include <mach-o/dyld.h> +# include <postmac.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# ifndef _LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# endif +# elif BYTE_ORDER == BIG_ENDIAN +# ifndef _BIG_ENDIAN +# define _BIG_ENDIAN +# endif +# elif BYTE_ORDER == PDP_ENDIAN +# ifndef _PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# endif +# define IOCHANNEL_TRANSFER_BSD_RENO +# define NO_PTHREAD_RTL +/* for NSGetArgc/Argv/Environ */ +# include <crt_externs.h> +#ifdef __cplusplus +extern "C" { +#endif +int macxp_resolveAlias(char *path, int buflen); +#ifdef __cplusplus +} +#endif +#endif + +#if !defined(_WIN32) && !defined(_WIN16) && !defined(OS2) && \ + !defined(LINUX) && !defined(NETBSD) && !defined(FREEBSD) && !defined(SCO) && \ + !defined(AIX) && !defined(HPUX) && \ + !defined(SOLARIS) && !defined(MACOSX) +# error "Target platform not specified!" +#endif + +#if defined(NETBSD) +#if defined _LITTLE_ENDIAN_OO +# define _OSL_BIGENDIAN +#elif defined _BIG_ENDIAN_OO +# define _OSL_LITENDIAN +#else +# error undetermined endianess +#endif +#else +#if defined _LITTLE_ENDIAN +# define _OSL_BIGENDIAN +#elif defined _BIG_ENDIAN +# define _OSL_LITENDIAN +#else +# error undetermined endianess +#endif +#endif + +#ifndef PTR_FD_SET +# define PTR_FD_SET(s) (&(s)) +#endif + +#ifndef NORMALIZE_TIMESPEC +# define NORMALIZE_TIMESPEC(timespec) \ + timespec . tv_sec += timespec . tv_nsec / 1000000000; \ + timespec . tv_nsec %= 1000000000; +#endif + +#ifndef SET_TIMESPEC +# define SET_TIMESPEC(timespec, sec, nsec) \ + timespec . tv_sec = (sec); \ + timespec . tv_nsec = (nsec); \ + NORMALIZE_TIMESPEC(timespec); +#endif + +#ifndef SLEEP_TIMESPEC +# define SLEEP_TIMESPEC(timespec) nanosleep(×pec, 0) +#endif + +#ifndef INIT_GROUPS +# define INIT_GROUPS(name, gid) ((setgid((gid)) == 0) && (initgroups((name), (gid)) == 0)) +#endif + +#ifndef PTHREAD_VALUE +# define PTHREAD_VALUE(t) (t) +#endif +#ifndef PTHREAD_NONE +# if (__GNUC__ < 4) && !defined(MACOSX) +extern pthread_t _pthread_none_; +# endif +# define PTHREAD_NONE _pthread_none_ +# ifndef PTHREAD_NONE_INIT +# define PTHREAD_NONE_INIT ((pthread_t)-1) +# endif +#endif + +#ifndef PTHREAD_ATTR_DEFAULT +# define PTHREAD_ATTR_DEFAULT NULL +#endif +#ifndef PTHREAD_MUTEXATTR_DEFAULT +# define PTHREAD_MUTEXATTR_DEFAULT NULL +#endif +#ifndef PTHREAD_CONDATTR_DEFAULT +# define PTHREAD_CONDATTR_DEFAULT NULL +#endif + +#ifndef PTHREAD_SIGACTION +# define PTHREAD_SIGACTION sigaction +#endif + +#ifndef STAT_PARENT +# define STAT_PARENT lstat +#endif + +/* socket options which might not be defined on all unx flavors */ +#ifndef SO_ACCEPTCONN +# define SO_ACCEPTCONN 0 +#endif +#ifndef SO_SNDLOWAT +# define SO_SNDLOWAT 0 +#endif +#ifndef SO_RCVLOWAT +# define SO_RCVLOWAT 0 +#endif +#ifndef SO_SNDTIMEO +# define SO_SNDTIMEO 0 +#endif +#ifndef SO_RCVTIMEO +# define SO_RCVTIMEO 0 +#endif +#ifndef SO_USELOOPBACK +# define SO_USELOOPBACK 0 +#endif +#ifndef MSG_MAXIOVLEN +# define MSG_MAXIOVLEN 0 +#endif + +/* BEGIN HACK */ +/* dummy define and declarations for IPX should be replaced by */ +/* original ipx headers when these are available for this platform */ + +#ifndef SA_FAMILY_DECL +# define SA_FAMILY_DECL short sa_family +#endif + +typedef struct sockaddr_ipx { + SA_FAMILY_DECL; + char sa_netnum[4]; + char sa_nodenum[6]; + unsigned short sa_socket; +} SOCKADDR_IPX; + +#define NSPROTO_IPX 1000 +#define NSPROTO_SPX 1256 +#define NSPROTO_SPXII 1257 + +/* END HACK */ + +#ifdef NO_PTHREAD_SEMAPHORES + +typedef struct +{ + pthread_mutex_t mutex; + pthread_cond_t increased; + int value; +} sem_t; +extern int sem_init(sem_t* sem, int pshared, unsigned int value); +extern int sem_destroy(sem_t* sem); +extern int sem_wait(sem_t* sem); +extern int sem_trywait(sem_t* sem); +extern int sem_post(sem_t* sem); + +#endif + +#ifdef NO_PTHREAD_RTL +#if !defined FREEBSD || (__FreeBSD_version < 500112) +struct passwd *getpwent_r(struct passwd *pwd, char *buffer, int buflen); +extern struct spwd *getspnam_r(const char *name, struct spwd *result, + char *buffer, int buflen); + +struct tm *localtime_r(const time_t *timep, struct tm *buffer); +struct tm *gmtime_r(const time_t *timep, struct tm *buffer); +#endif /* !defined FREEBSD || (__FreeBSD_version < 500112) */ +#if !defined(FREEBSD) || (__FreeBSD_version < 601103) +struct hostent *gethostbyname_r(const char *name, struct hostent *result, + char *buffer, int buflen, int *h_errnop); +#endif /* !defined(FREEBSD) || (__FreeBSD_version < 601103) */ +#endif + +#endif /* __OSL_SYSTEM_H__ */ + diff --git a/sal/osl/unx/tempfile.c b/sal/osl/unx/tempfile.c new file mode 100644 index 000000000000..e10fffaa5ce2 --- /dev/null +++ b/sal/osl/unx/tempfile.c @@ -0,0 +1,370 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/*****************************************************************/ +/* Includes */ +/*****************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "system.h" +#include <osl/file.h> +#include <osl/thread.h> +#include <rtl/ustrbuf.h> +#include <osl/diagnose.h> + +#ifndef _FILE_URL_H_ +#include "file_url.h" +#endif + +/*****************************************************************/ +/* osl_getTempFirURL */ +/*****************************************************************/ + +oslFileError SAL_CALL osl_getTempDirURL( rtl_uString** pustrTempDir ) +{ +#ifdef MACOSX + const char *pValue = getenv( "TMPDIR" ); + + /* If TMPDIR environment variable is not set, use "/tmp" instead + of P_tmpdir because its value is "/var/tmp" and it is not + deleted on system start up */ + if ( !pValue ) + pValue = "/tmp"; +#else + + const char *pValue = getenv( "TEMP" ); + + if ( !pValue ) + { + pValue = getenv( "TMP" ); +#if defined(SOLARIS) || defined (LINUX) || defined (FREEBSD) + if ( !pValue ) + pValue = P_tmpdir; +#endif + } +#endif /* MACOSX */ + + if ( pValue ) + { + oslFileError error; + rtl_uString *ustrTempPath = NULL; + + rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(ustrTempPath != NULL); + error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir ); + rtl_uString_release( ustrTempPath ); + + return error; + } + else + return osl_File_E_NOENT; +} + +/****************************************************************** + * Generates a random unique file name. We're using the scheme + * from the standard c-lib function mkstemp to generate a more + * or less random unique file name + * + * @param rand_name + * receives the random name + ******************************************************************/ + +static const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; +static const int COUNT_OF_LETTERS = sizeof(LETTERS)/sizeof(LETTERS[0]) - 1; + +#define RAND_NAME_LENGTH 6 + +static void osl_gen_random_name_impl_(rtl_uString** rand_name) +{ + static uint64_t value; + + char buffer[RAND_NAME_LENGTH]; + struct timeval tv; + uint64_t v; + int i; + + gettimeofday(&tv, NULL); + + value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid(); + + v = value; + + for (i = 0; i < RAND_NAME_LENGTH; i++) + { + buffer[i] = LETTERS[v % COUNT_OF_LETTERS]; + v /= COUNT_OF_LETTERS; + } + + rtl_string2UString( + rand_name, + buffer, + RAND_NAME_LENGTH, + RTL_TEXTENCODING_ASCII_US, + OSTRING_TO_OUSTRING_CVTFLAGS); + OSL_ASSERT(*rand_name != NULL); +} + +/***************************************************************** + * Helper function + * Either use the directory provided or the result of + * osl_getTempDirUrl and return it as system path and file url + ****************************************************************/ + +static oslFileError osl_setup_base_directory_impl_( + rtl_uString* pustrDirectoryURL, + rtl_uString** ppustr_base_dir) +{ + rtl_uString* dir_url = 0; + rtl_uString* dir = 0; + oslFileError error = osl_File_E_None; + + if (pustrDirectoryURL) + rtl_uString_assign(&dir_url, pustrDirectoryURL); + else + error = osl_getTempDirURL(&dir_url); + + if (osl_File_E_None == error) + { + error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir, FURL_DENY_RELATIVE); + rtl_uString_release(dir_url); + } + + if (osl_File_E_None == error) + { + rtl_uString_assign(ppustr_base_dir, dir); + rtl_uString_release(dir); + } + + return error; +} + +/***************************************************************** + * osl_setup_createTempFile_impl + * validate input parameter, setup variables + ****************************************************************/ + + static oslFileError osl_setup_createTempFile_impl_( + rtl_uString* pustrDirectoryURL, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL, + rtl_uString** ppustr_base_dir, + sal_Bool* b_delete_on_close) + { + oslFileError osl_error; + + OSL_PRECOND(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!"); + + if ((0 == pHandle) && (0 == ppustrTempFileURL)) + { + osl_error = osl_File_E_INVAL; + } + else + { + osl_error = osl_setup_base_directory_impl_( + pustrDirectoryURL, ppustr_base_dir); + + *b_delete_on_close = (0 == ppustrTempFileURL); + } + + return osl_error; + } + +/***************************************************************** + * Create a unique file in the specified directory and return + * it's name + ****************************************************************/ + +static oslFileError osl_create_temp_file_impl_( + const rtl_uString* pustr_base_directory, + oslFileHandle* file_handle, + rtl_uString** ppustr_temp_file_name) +{ + rtl_uString* rand_name = 0; + sal_uInt32 len_base_dir = 0; + rtl_uString* tmp_file_path = 0; + rtl_uString* tmp_file_url = 0; + sal_Int32 capacity = 0; + oslFileError osl_error = osl_File_E_None; + sal_Int32 offset_file_name; + const sal_Unicode* puchr; + + OSL_PRECOND(pustr_base_directory, "Invalid Parameter"); + OSL_PRECOND(file_handle, "Invalid Parameter"); + OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter"); + + len_base_dir = rtl_uString_getLength(pustr_base_directory); + + rtl_uStringbuffer_newFromStr_WithLength( + &tmp_file_path, + rtl_uString_getStr((rtl_uString*)pustr_base_directory), + len_base_dir); + + rtl_uStringbuffer_ensureCapacity( + &tmp_file_path, + &capacity, + (len_base_dir + 1 + RAND_NAME_LENGTH)); + + offset_file_name = len_base_dir; + + puchr = rtl_uString_getStr(tmp_file_path); + + /* ensure that the last character is a '/' */ + + if ((sal_Unicode)'/' != puchr[len_base_dir - 1]) + { + rtl_uStringbuffer_insert_ascii( + &tmp_file_path, + &capacity, + len_base_dir, + "/", + 1); + + offset_file_name++; + } + + while(1) /* try until success */ + { + osl_gen_random_name_impl_(&rand_name); + + rtl_uStringbuffer_insert( + &tmp_file_path, + &capacity, + offset_file_name, + rtl_uString_getStr(rand_name), + rtl_uString_getLength(rand_name)); + + osl_error = osl_getFileURLFromSystemPath( + tmp_file_path, &tmp_file_url); + + if (osl_File_E_None == osl_error) + { + /* RW permission for the user only! */ + mode_t old_mode = umask(077); + + osl_error = osl_openFile( + tmp_file_url, + file_handle, + osl_File_OpenFlag_Read | + osl_File_OpenFlag_Write | + osl_File_OpenFlag_Create); + + umask(old_mode); + } + + /* in case of error osl_File_E_EXIST we simply try again else we give up */ + + if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST)) + { + if (rand_name) + rtl_uString_release(rand_name); + + if (tmp_file_url) + rtl_uString_release(tmp_file_url); + + break; + } + } /* while(1) */ + + if (osl_File_E_None == osl_error) + rtl_uString_assign(ppustr_temp_file_name, tmp_file_path); + + if (tmp_file_path) + rtl_uString_release(tmp_file_path); + + return osl_error; +} + +/***************************************************************** + * osl_createTempFile + *****************************************************************/ + +oslFileError SAL_CALL osl_createTempFile( + rtl_uString* pustrDirectoryURL, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL) +{ + rtl_uString* base_directory = 0; + rtl_uString* temp_file_name = 0; + oslFileHandle temp_file_handle; + sal_Bool b_delete_on_close; + oslFileError osl_error; + + osl_error = osl_setup_createTempFile_impl_( + pustrDirectoryURL, + pHandle, + ppustrTempFileURL, + &base_directory, + &b_delete_on_close); + + if (osl_File_E_None != osl_error) + return osl_error; + + osl_error = osl_create_temp_file_impl_( + base_directory, &temp_file_handle, &temp_file_name); + + if (osl_File_E_None == osl_error) + { + rtl_uString* temp_file_url = 0; + + /* assuming this works */ + osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url); + + if (b_delete_on_close) + { + osl_error = osl_removeFile(temp_file_url); + + if (osl_File_E_None == osl_error) + *pHandle = temp_file_handle; + else + osl_closeFile(temp_file_handle); + } + else + { + if (pHandle) + *pHandle = temp_file_handle; + else + osl_closeFile(temp_file_handle); + + rtl_uString_assign(ppustrTempFileURL, temp_file_url); + } + + if (temp_file_url) + rtl_uString_release(temp_file_url); + + if (temp_file_name) + rtl_uString_release(temp_file_name); + } + + if (base_directory) + rtl_uString_release(base_directory); + + return osl_error; +} diff --git a/sal/osl/unx/thread.c b/sal/osl/unx/thread.c new file mode 100644 index 000000000000..fe53915b792f --- /dev/null +++ b/sal/osl/unx/thread.c @@ -0,0 +1,1035 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" +#include <string.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/nlsupport.h> +#ifndef _RTL_TEXTENC_H_ +#include <rtl/textenc.h> +#endif + +/**************************************************************************** + * @@@ TODO @@@ + * + * (1) 'osl_thread_priority_init_Impl()' + * - insane assumption that initializing caller is main thread + * - use _POSIX_THREAD_PRIORITY_SCHEDULING, not NO_PTHREAD_PRIORITY (?) + * - POSIX doesn't require defined prio's for SCHED_OTHER (!) + * - use SCHED_RR instead of SCHED_OTHER for defined behaviour (?) + * (2) 'oslThreadIdentifier' and '{insert|remove|lookup}ThreadId()' + * - cannot reliably be applied to 'alien' threads; + * - memory leak for 'alien' thread 'HashEntry's; + * - use 'PTHREAD_VALUE(pthread_t)' as identifier instead (?) + * - if yes, change 'oslThreadIdentifier' to 'intptr_t' or similar + * (3) 'oslSigAlarmHandler()' (#71232#) + * - [Under Solaris we get SIGALRM in e.g. pthread_join which terminates + * the process. So we initialize our signal handling module and do + * register a SIGALRM Handler which catches and ignores it] + * - should this still happen, 'signal.c' needs to be fixed instead. + * + ****************************************************************************/ + +/*****************************************************************************/ +/* Internal data structures and functions */ +/*****************************************************************************/ + +#define THREADIMPL_FLAGS_TERMINATE 0x00001 +#define THREADIMPL_FLAGS_STARTUP 0x00002 +#define THREADIMPL_FLAGS_SUSPENDED 0x00004 +#define THREADIMPL_FLAGS_ACTIVE 0x00008 +#define THREADIMPL_FLAGS_ATTACHED 0x00010 +#define THREADIMPL_FLAGS_DESTROYED 0x00020 + +typedef struct osl_thread_impl_st +{ + pthread_t m_hThread; + sal_uInt16 m_Ident; /* @@@ see TODO @@@ */ + short m_Flags; + oslWorkerFunction m_WorkerFunction; + void* m_pData; + pthread_mutex_t m_Lock; + pthread_cond_t m_Cond; +} Thread_Impl; + +struct osl_thread_priority_st +{ + int m_Highest; + int m_Above_Normal; + int m_Normal; + int m_Below_Normal; + int m_Lowest; +}; + +#define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 } +static void osl_thread_priority_init_Impl (void); + +struct osl_thread_textencoding_st +{ + pthread_key_t m_key; /* key to store thread local text encoding */ + rtl_TextEncoding m_default; /* the default text encoding */ +}; + +#define OSL_THREAD_TEXTENCODING_INITIALIZER { 0, RTL_TEXTENCODING_DONTKNOW } +static void osl_thread_textencoding_init_Impl (void); + +struct osl_thread_global_st +{ + pthread_once_t m_once; + struct osl_thread_priority_st m_priority; + struct osl_thread_textencoding_st m_textencoding; +}; + +static struct osl_thread_global_st g_thread = +{ + PTHREAD_ONCE_INIT, + OSL_THREAD_PRIORITY_INITIALIZER, + OSL_THREAD_TEXTENCODING_INITIALIZER +}; + +static void osl_thread_init_Impl (void); + +static Thread_Impl* osl_thread_construct_Impl (void); +static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl); + +static void* osl_thread_start_Impl (void * pData); +static void osl_thread_cleanup_Impl (void * pData); + +static oslThread osl_thread_create_Impl ( + oslWorkerFunction pWorker, void * pThreadData, short nFlags); + +static void osl_thread_join_cleanup_Impl (void * opaque); +static void osl_thread_wait_cleanup_Impl (void * opaque); + +/* @@@ see TODO @@@ */ +static sal_uInt16 insertThreadId (pthread_t hThread); +static sal_uInt16 lookupThreadId (pthread_t hThread); +static void removeThreadId (pthread_t hThread); + +/*****************************************************************************/ +/* osl_thread_init_Impl */ +/*****************************************************************************/ +static void osl_thread_init_Impl (void) +{ + osl_thread_priority_init_Impl(); + osl_thread_textencoding_init_Impl(); +} + +/*****************************************************************************/ +/* osl_thread_join_cleanup_Impl */ +/*****************************************************************************/ +static void osl_thread_join_cleanup_Impl (void * opaque) +{ + pthread_t hThread = (pthread_t)(opaque); + pthread_detach (hThread); +} + +/*****************************************************************************/ +/* osl_thread_wait_cleanup_Impl */ +/*****************************************************************************/ +static void osl_thread_wait_cleanup_Impl (void * opaque) +{ + pthread_mutex_t * pMutex = (pthread_mutex_t*)(opaque); + pthread_mutex_unlock (pMutex); +} + +/*****************************************************************************/ +/* osl_thread_construct_Impl */ +/*****************************************************************************/ +Thread_Impl* osl_thread_construct_Impl (void) +{ + Thread_Impl* pImpl = malloc (sizeof(Thread_Impl)); + if (pImpl) + { + memset (pImpl, 0, sizeof(Thread_Impl)); + + pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT); + pthread_cond_init (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT); + } + return (pImpl); +} + +/*****************************************************************************/ +/* osl_thread_destruct_Impl */ +/*****************************************************************************/ +static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl) +{ + OSL_ASSERT(ppImpl); + if (*ppImpl) + { + pthread_cond_destroy (&((*ppImpl)->m_Cond)); + pthread_mutex_destroy (&((*ppImpl)->m_Lock)); + + free (*ppImpl); + (*ppImpl) = 0; + } +} + +/*****************************************************************************/ +/* osl_thread_cleanup_Impl */ +/*****************************************************************************/ +static void osl_thread_cleanup_Impl (void* pData) +{ + pthread_t thread; + int attached; + int destroyed; + Thread_Impl* pImpl= (Thread_Impl*)pData; + + pthread_mutex_lock (&(pImpl->m_Lock)); + + thread = pImpl->m_hThread; + attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0; + destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0; + pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + /* release oslThreadIdentifier @@@ see TODO @@@ */ + removeThreadId (thread); + + if (attached) + { + pthread_detach (thread); + } + + if (destroyed) + { + osl_thread_destruct_Impl (&pImpl); + } +} + +/*****************************************************************************/ +/* osl_thread_start_Impl */ +/*****************************************************************************/ +static void* osl_thread_start_Impl (void* pData) +{ + int terminate; + Thread_Impl* pImpl= (Thread_Impl*)pData; + + OSL_ASSERT(pImpl); + + pthread_mutex_lock (&(pImpl->m_Lock)); + + /* install cleanup handler */ + pthread_cleanup_push (osl_thread_cleanup_Impl, pData); + + /* request oslThreadIdentifier @@@ see TODO @@@ */ + pImpl->m_Ident = insertThreadId (pImpl->m_hThread); + + /* signal change from STARTUP to ACTIVE state */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP; + pImpl->m_Flags |= THREADIMPL_FLAGS_ACTIVE; + pthread_cond_signal (&(pImpl->m_Cond)); + + /* Check if thread is started in SUSPENDED state */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + pthread_cleanup_pop (0); + } + + /* check for SUSPENDED to TERMINATE state change */ + terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + if (!terminate) + { + /* call worker function */ + pImpl->m_WorkerFunction(pImpl->m_pData); + } + + /* call cleanup handler and leave */ + pthread_cleanup_pop (1); + return (0); +} + +/*****************************************************************************/ +/* osl_thread_create_Impl */ +/*****************************************************************************/ +static oslThread osl_thread_create_Impl ( + oslWorkerFunction pWorker, + void* pThreadData, + short nFlags) +{ + Thread_Impl* pImpl; + int nRet=0; + + pImpl = osl_thread_construct_Impl(); + if (!pImpl) + return (0); /* ENOMEM */ + + pImpl->m_WorkerFunction = pWorker; + pImpl->m_pData = pThreadData; + pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP; + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if ((nRet = pthread_create ( + &(pImpl->m_hThread), + PTHREAD_ATTR_DEFAULT, + osl_thread_start_Impl, + (void*)(pImpl))) != 0) + { + OSL_TRACE("osl_thread_create_Impl(): errno: %d, %s\n", + nRet, strerror(nRet)); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + osl_thread_destruct_Impl (&pImpl); + + return (0); + } + + /* wait for change from STARTUP to ACTIVE state */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP) + { + /* wait until STARTUP flag is cleared */ + pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + pthread_cleanup_pop (0); + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + return ((oslThread)(pImpl)); +} + +/*****************************************************************************/ +/* osl_createThread */ +/*****************************************************************************/ +oslThread osl_createThread ( + oslWorkerFunction pWorker, + void * pThreadData) +{ + return osl_thread_create_Impl ( + pWorker, + pThreadData, + THREADIMPL_FLAGS_ATTACHED); +} + +/*****************************************************************************/ +/* osl_createSuspendedThread */ +/*****************************************************************************/ +oslThread osl_createSuspendedThread ( + oslWorkerFunction pWorker, + void * pThreadData) +{ + return osl_thread_create_Impl ( + pWorker, + pThreadData, + THREADIMPL_FLAGS_ATTACHED | + THREADIMPL_FLAGS_SUSPENDED ); +} + +/*****************************************************************************/ +/* osl_destroyThread */ +/*****************************************************************************/ +void SAL_CALL osl_destroyThread(oslThread Thread) +{ + if (Thread != NULL) { + Thread_Impl * impl = (Thread_Impl *) Thread; + int active; + pthread_mutex_lock(&impl->m_Lock); + active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0; + impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED; + pthread_mutex_unlock(&impl->m_Lock); + if (!active) { + osl_thread_destruct_Impl(&impl); + } + } +} + +/*****************************************************************************/ +/* osl_resumeThread */ +/*****************************************************************************/ +void SAL_CALL osl_resumeThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* clear SUSPENDED flag */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED; + pthread_cond_signal (&(pImpl->m_Cond)); + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +/*****************************************************************************/ +/* osl_suspendThread */ +/*****************************************************************************/ +void SAL_CALL osl_suspendThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED; + + if (pthread_equal (pthread_self(), pImpl->m_hThread)) + { + /* self suspend */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + pthread_cleanup_pop (0); + } + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +/*****************************************************************************/ +/* osl_isThreadRunning */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread) +{ + sal_Bool active; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + if (!pImpl) + return sal_False; + + pthread_mutex_lock (&(pImpl->m_Lock)); + active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0); + pthread_mutex_unlock (&(pImpl->m_Lock)); + + return (active); +} + +/*****************************************************************************/ +/* osl_joinWithThread */ +/*****************************************************************************/ +void SAL_CALL osl_joinWithThread(oslThread Thread) +{ + pthread_t thread; + int attached; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + if (!pImpl) + return; + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pthread_equal (pthread_self(), pImpl->m_hThread)) + { + /* self join */ + pthread_mutex_unlock (&(pImpl->m_Lock)); + return; /* EDEADLK */ + } + + thread = pImpl->m_hThread; + attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0); + pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED; + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + if (attached) + { + /* install cleanup handler to ensure consistent flags and state */ + pthread_cleanup_push ( + osl_thread_join_cleanup_Impl, (void*)thread); + + /* join */ + pthread_join (thread, NULL); + + /* remove cleanup handler */ + pthread_cleanup_pop (0); + } +} + +/*****************************************************************************/ +/* osl_terminateThread */ +/*****************************************************************************/ +void SAL_CALL osl_terminateThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* clear SUSPENDED flag */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED; + pthread_cond_signal (&(pImpl->m_Cond)); + } + + pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE; + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +/*****************************************************************************/ +/* osl_scheduleThread */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread) +{ + int terminate; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return sal_False; /* EINVAL */ + + OSL_ASSERT(pthread_equal (pthread_self(), pImpl->m_hThread)); + if (!(pthread_equal (pthread_self(), pImpl->m_hThread))) + return sal_False; /* EINVAL */ + + pthread_testcancel(); + pthread_mutex_lock (&(pImpl->m_Lock)); + + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + pthread_cleanup_pop (0); + } + + terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0); + + pthread_mutex_unlock(&(pImpl->m_Lock)); + pthread_testcancel(); + + return (terminate == 0); +} + +/*****************************************************************************/ +/* osl_waitThread */ +/*****************************************************************************/ +void SAL_CALL osl_waitThread(const TimeValue* pDelay) +{ + if (pDelay) + { + struct timespec delay; + + SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec); + + SLEEP_TIMESPEC(delay); + } +} + +/*****************************************************************************/ +/* osl_yieldThread */ +/* + Note that POSIX scheduling _really_ requires threads to call this + functions, since a thread only reschedules to other thread, when + it blocks (sleep, blocking I/O) OR calls sched_yield(). +*/ +/*****************************************************************************/ +void SAL_CALL osl_yieldThread() +{ + sched_yield(); +} + +/*****************************************************************************/ +/* osl_getThreadIdentifier @@@ see TODO @@@ */ +/*****************************************************************************/ + +#define HASHID(x) ((unsigned int)PTHREAD_VALUE(x) % HashSize) + +typedef struct _HashEntry +{ + pthread_t Handle; + sal_uInt16 Ident; + struct _HashEntry *Next; +} HashEntry; + +static HashEntry* HashTable[31]; +static int HashSize = sizeof(HashTable) / sizeof(HashTable[0]); + +static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER; + +static sal_uInt16 LastIdent = 0; + +static sal_uInt16 lookupThreadId (pthread_t hThread) +{ + HashEntry *pEntry; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + { + pthread_mutex_unlock(&HashLock); + return (pEntry->Ident); + } + pEntry = pEntry->Next; + } + + pthread_mutex_unlock(&HashLock); + + return (0); +} + +static sal_uInt16 insertThreadId (pthread_t hThread) +{ + HashEntry *pEntry, *pInsert = NULL; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + break; + + pInsert = pEntry; + pEntry = pEntry->Next; + } + + if (pEntry == NULL) + { + pEntry = (HashEntry*) calloc(sizeof(HashEntry), 1); + + pEntry->Handle = hThread; + + ++ LastIdent; + + if ( LastIdent == 0 ) + LastIdent = 1; + + pEntry->Ident = LastIdent; + + if (pInsert) + pInsert->Next = pEntry; + else + HashTable[HASHID(hThread)] = pEntry; + } + + pthread_mutex_unlock(&HashLock); + + return (pEntry->Ident); +} + +static void removeThreadId (pthread_t hThread) +{ + HashEntry *pEntry, *pRemove = NULL; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + break; + + pRemove = pEntry; + pEntry = pEntry->Next; + } + + if (pEntry != NULL) + { + if (pRemove) + pRemove->Next = pEntry->Next; + else + HashTable[HASHID(hThread)] = pEntry->Next; + + free(pEntry); + } + + pthread_mutex_unlock(&HashLock); +} + +oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + sal_uInt16 Ident; + + if (pImpl) + Ident = pImpl->m_Ident; + else + { + /* current thread */ + pthread_t current = pthread_self(); + + Ident = lookupThreadId (current); + if (Ident == 0) + /* @@@ see TODO: alien pthread_self() @@@ */ + Ident = insertThreadId (current); + } + + return ((oslThreadIdentifier)(Ident)); +} + +/***************************************************************************** + @@@ see TODO @@@ + osl_thread_priority_init_Impl + + set the base-priority of the main-thread to + oslThreadPriorityNormal (64) since 0 (lowest) is + the system default. This behaviour collides with + our enum-priority definition (highest..normal..lowest). + A normaluser will expect the main-thread of an app. + to have the "normal" priority. + +*****************************************************************************/ +static void osl_thread_priority_init_Impl (void) +{ +#ifndef NO_PTHREAD_PRIORITY + struct sched_param param; + int policy=0; + int nRet=0; + +/* @@@ see TODO: calling thread may not be main thread @@@ */ + + if ((nRet = pthread_getschedparam(pthread_self(), &policy, ¶m)) != 0) + { + OSL_TRACE("failed to get priority of thread [%s]\n",strerror(nRet)); + return; + } + +#if defined (SOLARIS) + if ( policy >= _SCHED_NEXT) + { + /* mfe: pthread_getschedparam on Solaris has a possible Bug */ + /* one gets 959917873 as the policy */ + /* so set the policy to a default one */ + policy=SCHED_OTHER; + } +#endif /* SOLARIS */ + + if ((nRet = sched_get_priority_min(policy) ) != -1) + { + OSL_TRACE("Min Prioriy for policy '%i' == '%i'\n",policy,nRet); + g_thread.m_priority.m_Lowest=nRet; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + fprintf(stderr,"failed to get min sched param [%s]\n",strerror(errno)); + } +#endif /* OSL_DEBUG_LEVEL */ + + if ((nRet = sched_get_priority_max(policy) ) != -1) + { + OSL_TRACE("Max Prioriy for policy '%i' == '%i'\n",policy,nRet); + g_thread.m_priority.m_Highest=nRet; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + fprintf(stderr,"failed to get max sched param [%s]\n",strerror(errno)); + } +#endif /* OSL_DEBUG_LEVEL */ + + g_thread.m_priority.m_Normal = + (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2; + g_thread.m_priority.m_Below_Normal = + (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal) / 2; + g_thread.m_priority.m_Above_Normal = + (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2; + +/* @@@ set prio of calling (not main) thread (?) @@@ */ + + param.sched_priority= g_thread.m_priority.m_Normal; + + if ((nRet = pthread_setschedparam(pthread_self(), policy, ¶m)) != 0) + { + OSL_TRACE("failed to change base priority of thread [%s]\n",strerror(nRet)); + OSL_TRACE("Thread ID '%i', Policy '%i', Priority '%i'\n",pthread_self(),policy,param.sched_priority); + } + +#endif /* NO_PTHREAD_PRIORITY */ +} + +/*****************************************************************************/ +/* osl_setThreadPriority */ +/* + Impl-Notes: contrary to solaris-docu, which claims + valid priority-levels from 0 .. INT_MAX, only the + range 0..127 is accepted. (0 lowest, 127 highest) +*/ +/*****************************************************************************/ +void SAL_CALL osl_setThreadPriority ( + oslThread Thread, + oslThreadPriority Priority) +{ +#ifndef NO_PTHREAD_PRIORITY + + struct sched_param Param; + int policy; + int nRet; + +#endif /* NO_PTHREAD_PRIORITY */ + + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + +#ifdef NO_PTHREAD_PRIORITY + (void) Priority; /* unused */ +#else /* NO_PTHREAD_PRIORITY */ + + if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0) + return; /* ESRCH */ + +#if defined (SOLARIS) + if ( policy >= _SCHED_NEXT) + { + /* mfe: pthread_getschedparam on Solaris has a possible Bug */ + /* one gets 959917873 as the policy */ + /* so set the policy to a default one */ + policy=SCHED_OTHER; + } +#endif /* SOLARIS */ + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + switch(Priority) + { + case osl_Thread_PriorityHighest: + Param.sched_priority= g_thread.m_priority.m_Highest; + break; + + case osl_Thread_PriorityAboveNormal: + Param.sched_priority= g_thread.m_priority.m_Above_Normal; + break; + + case osl_Thread_PriorityNormal: + Param.sched_priority= g_thread.m_priority.m_Normal; + break; + + case osl_Thread_PriorityBelowNormal: + Param.sched_priority= g_thread.m_priority.m_Below_Normal; + break; + + case osl_Thread_PriorityLowest: + Param.sched_priority= g_thread.m_priority.m_Lowest; + break; + + case osl_Thread_PriorityUnknown: + OSL_ASSERT(sal_False); /* only fools try this...*/ + + /* let release-version behave friendly */ + return; + + default: + /* enum expanded, but forgotten here...*/ + OSL_ENSURE(sal_False,"osl_setThreadPriority : unknown priority\n"); + + /* let release-version behave friendly */ + return; + } + + if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0) + { + OSL_TRACE("failed to change thread priority [%s]\n",strerror(nRet)); + } + +#endif /* NO_PTHREAD_PRIORITY */ +} + +/*****************************************************************************/ +/* osl_getThreadPriority */ +/*****************************************************************************/ +oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread) +{ +#ifndef NO_PTHREAD_PRIORITY + + struct sched_param Param; + int Policy; + +#endif /* NO_PTHREAD_PRIORITY */ + + oslThreadPriority Priority = osl_Thread_PriorityNormal; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return osl_Thread_PriorityUnknown; /* EINVAL */ + +#ifndef NO_PTHREAD_PRIORITY + + if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0) + return osl_Thread_PriorityUnknown; /* ESRCH */ + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + /* map pthread priority to enum */ + if (Param.sched_priority==g_thread.m_priority.m_Highest) + { + /* 127 - highest */ + Priority= osl_Thread_PriorityHighest; + } + else if (Param.sched_priority > g_thread.m_priority.m_Normal) + { + /* 65..126 - above normal */ + Priority= osl_Thread_PriorityAboveNormal; + } + else if (Param.sched_priority == g_thread.m_priority.m_Normal) + { + /* normal */ + Priority= osl_Thread_PriorityNormal; + } + else if (Param.sched_priority > g_thread.m_priority.m_Lowest) + { + /* 63..1 -below normal */ + Priority= osl_Thread_PriorityBelowNormal; + } + else if (Param.sched_priority == g_thread.m_priority.m_Lowest) + { + /* 0 - lowest */ + Priority= osl_Thread_PriorityLowest; + } + else + { + /* unknown */ + Priority= osl_Thread_PriorityUnknown; + } + +#endif /* NO_PTHREAD_PRIORITY */ + + return Priority; +} + +/*****************************************************************************/ +/* osl_createThreadKey */ +/*****************************************************************************/ +oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback ) +{ + pthread_key_t key; + + if (pthread_key_create(&key, pCallback) != 0) + key = 0; + + return ((oslThreadKey)key); +} + +/*****************************************************************************/ +/* osl_destroyThreadKey */ +/*****************************************************************************/ +void SAL_CALL osl_destroyThreadKey(oslThreadKey Key) +{ + pthread_key_delete((pthread_key_t)Key); +} + +/*****************************************************************************/ +/* osl_getThreadKeyData */ +/*****************************************************************************/ +void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key) +{ + return (pthread_getspecific((pthread_key_t)Key)); +} + +/*****************************************************************************/ +/* osl_setThreadKeyData */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData) +{ + return (pthread_setspecific((pthread_key_t)Key, pData) == 0); +} + +/*****************************************************************************/ +/* Thread Local Text Encoding */ +/*****************************************************************************/ +static void osl_thread_textencoding_init_Impl (void) +{ + rtl_TextEncoding defaultEncoding; + const char * pszEncoding; + + /* create thread specific data key */ + pthread_key_create (&(g_thread.m_textencoding.m_key), NULL); + + /* determine default text encoding */ + pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING"); + if (pszEncoding) + defaultEncoding = atoi(pszEncoding); + else + defaultEncoding = osl_getTextEncodingFromLocale(NULL); + + OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW); + + /* + Tools string functions call abort() on an unknown encoding so ASCII + is a meaningfull fallback regardless wether the assertion makes sense. + */ + + if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding ) + defaultEncoding = RTL_TEXTENCODING_ASCII_US; + + g_thread.m_textencoding.m_default = defaultEncoding; +} + +/*****************************************************************************/ +/* osl_getThreadTextEncoding */ +/*****************************************************************************/ +rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding() +{ + rtl_TextEncoding threadEncoding; + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + /* check for thread specific encoding, use default if not set */ + threadEncoding = SAL_INT_CAST( + rtl_TextEncoding, + (sal_uIntPtr) pthread_getspecific(g_thread.m_textencoding.m_key)); + if (0 == threadEncoding) + threadEncoding = g_thread.m_textencoding.m_default; + + return threadEncoding; +} + +/*****************************************************************************/ +/* osl_setThreadTextEncoding */ +/*****************************************************************************/ +rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding) +{ + rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding(); + + /* save encoding in thread local storage */ + pthread_setspecific ( + g_thread.m_textencoding.m_key, + (void*) SAL_INT_CAST(sal_uIntPtr, Encoding)); + + return oldThreadEncoding; +} diff --git a/sal/osl/unx/time.c b/sal/osl/unx/time.c new file mode 100644 index 000000000000..c1a98a6b87a9 --- /dev/null +++ b/sal/osl/unx/time.c @@ -0,0 +1,269 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/time.h> + +/* FIXME: detection should be done in configure script */ +#if defined(MACOSX) || defined(FREEBSD) || defined(NETBSD) || defined(LINUX) +#define STRUCT_TM_HAS_GMTOFF 1 + +#elif defined(SOLARIS) +#define HAS_ALTZONE 1 +#endif + +/*-------------------------------------------------- + * osl_getSystemTime + *-------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getSystemTime(TimeValue* TimeValue) +{ + struct timeval tp; + + /* FIXME: use higher resolution */ + gettimeofday(&tp, NULL); + + TimeValue->Seconds = tp.tv_sec; + TimeValue->Nanosec = tp.tv_usec * 1000; + + return (sal_True); +} + + +/*-------------------------------------------------- + * osl_getDateTimeFromTimeValue + *-------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getDateTimeFromTimeValue( TimeValue* pTimeVal, oslDateTime* pDateTime ) +{ + struct tm *pSystemTime; + struct tm tmBuf; + time_t atime; + + atime = (time_t)pTimeVal->Seconds; + + /* Convert time from type time_t to struct tm */ + pSystemTime = gmtime_r( &atime, &tmBuf ); + + + /* Convert struct tm to struct oslDateTime */ + if ( pSystemTime != NULL ) + { + pDateTime->NanoSeconds = pTimeVal->Nanosec; + pDateTime->Seconds = pSystemTime->tm_sec; + pDateTime->Minutes = pSystemTime->tm_min; + pDateTime->Hours = pSystemTime->tm_hour; + pDateTime->Day = pSystemTime->tm_mday; + pDateTime->DayOfWeek = pSystemTime->tm_wday; + pDateTime->Month = pSystemTime->tm_mon + 1; + pDateTime->Year = pSystemTime->tm_year + 1900; + + return sal_True; + } + + return sal_False; +} + +/*-------------------------------------------------- + * osl_getTimeValueFromDateTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getTimeValueFromDateTime( oslDateTime* pDateTime, TimeValue* pTimeVal ) +{ + struct tm aTime; + time_t nSeconds; + + /* Convert struct oslDateTime to struct tm */ + aTime.tm_sec = pDateTime->Seconds; + aTime.tm_min = pDateTime->Minutes; + aTime.tm_hour = pDateTime->Hours; + aTime.tm_mday = pDateTime->Day; + aTime.tm_wday = pDateTime->DayOfWeek; + + if ( pDateTime->Month > 0 ) + aTime.tm_mon = pDateTime->Month - 1; + else + return sal_False; + + if ( pDateTime->Year >= 1900 ) + aTime.tm_year = pDateTime->Year - 1900; + else + return sal_False; + + aTime.tm_isdst = -1; + aTime.tm_wday = 0; + aTime.tm_yday = 0; + + /* Convert time to calendar value */ + nSeconds = mktime( &aTime ); + + /* + * mktime expects the struct tm to be in local timezone, so we have to adjust + * the returned value to be timezone neutral. + */ + + if ( nSeconds != (time_t) -1 ) + { + time_t bias; + + /* timezone corrections */ + tzset(); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - aTime.tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = aTime.tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = aTime.tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + pTimeVal->Seconds = nSeconds; + pTimeVal->Nanosec = pDateTime->NanoSeconds; + + if ( nSeconds > bias ) + pTimeVal->Seconds -= bias; + + return sal_True; + } + + return sal_False; +} + + +/*-------------------------------------------------- + * osl_getLocalTimeFromSystemTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getLocalTimeFromSystemTime( TimeValue* pSystemTimeVal, TimeValue* pLocalTimeVal ) +{ + struct tm *pLocalTime; + struct tm tmBuf; + time_t bias; + time_t atime; + + atime = (time_t) pSystemTimeVal->Seconds; + pLocalTime = localtime_r( &atime, &tmBuf ); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - pLocalTime->tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = pLocalTime->tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = pLocalTime->tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + if ( (sal_Int64) pSystemTimeVal->Seconds > bias ) + { + pLocalTimeVal->Seconds = pSystemTimeVal->Seconds - bias; + pLocalTimeVal->Nanosec = pSystemTimeVal->Nanosec; + + return sal_True; + } + + return sal_False; +} + +/*-------------------------------------------------- + * osl_getSystemTimeFromLocalTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getSystemTimeFromLocalTime( TimeValue* pLocalTimeVal, TimeValue* pSystemTimeVal ) +{ + struct tm *pLocalTime; + struct tm tmBuf; + time_t bias; + time_t atime; + + atime = (time_t) pLocalTimeVal->Seconds; + + /* Convert atime, which is a local time, to it's GMT equivalent. Then, get + * the timezone offset for the local time for the GMT equivalent time. Note + * that we cannot directly use local time to determine the timezone offset + * because GMT is the only reliable time that we can determine timezone + * offset from. + */ + + atime = mktime( gmtime_r( &atime, &tmBuf ) ); + pLocalTime = localtime_r( &atime, &tmBuf ); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - pLocalTime->tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = pLocalTime->tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = pLocalTime->tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + if ( (sal_Int64) pLocalTimeVal->Seconds + bias > 0 ) + { + pSystemTimeVal->Seconds = pLocalTimeVal->Seconds + bias; + pSystemTimeVal->Nanosec = pLocalTimeVal->Nanosec; + + return sal_True; + } + + return sal_False; +} + + + +static struct timeval startTime; +static sal_Bool bGlobalTimer = sal_False; + +sal_uInt32 SAL_CALL osl_getGlobalTimer() +{ + struct timeval currentTime; + sal_uInt32 nSeconds; + + // FIXME: not thread safe !! + if ( bGlobalTimer == sal_False ) + { + gettimeofday( &startTime, NULL ); + bGlobalTimer=sal_True; + } + + gettimeofday( ¤tTime, NULL ); + + nSeconds = (sal_uInt32)( currentTime.tv_sec - startTime.tv_sec ); + + return ( nSeconds * 1000 ) + (long) (( currentTime.tv_usec - startTime.tv_usec) / 1000 ); +} diff --git a/sal/osl/unx/util.c b/sal/osl/unx/util.c new file mode 100644 index 000000000000..5ba04db56021 --- /dev/null +++ b/sal/osl/unx/util.c @@ -0,0 +1,350 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef SOLARIS +#include <sys/sockio.h> +#endif + +#include "osl/util.h" + + + +/*****************************************************************************/ +/* Static Module Functions */ +/*****************************************************************************/ + +static int osl_getHWAddr(const char *ifname, char* hard_addr); +static int osl_checkAddr(const char* addr); + + +/*****************************************************************************/ +/* osl_getEthernetAddress */ +/*****************************************************************************/ + +sal_Bool SAL_CALL osl_getEthernetAddress( sal_uInt8 * pAddr ) +{ + char buff[1024]; + char hard_addr[64]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + int so; + +#ifdef SOLARIS + /** algorithm doesn't work on solaris */ + return sal_False; +#else + + if ( pAddr == 0 ) + { + return sal_False; + } + + + /* + * All we need is ... a network file descriptor. + * Normally, this is a very socket. + */ + + so = socket(AF_INET, SOCK_DGRAM, 0); + + + /* + * The first thing we have to do, get the interface configuration. + * It is a list of attached/configured interfaces + */ + + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if ( ioctl(so, SIOCGIFCONF, &ifc) < 0 ) + { +/* fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));*/ + close(so); + return sal_False; + } + + close(so); + + /* + * For each of the interfaces in the interface list, + * try to get the hardware address + */ + + ifr = ifc.ifc_req; + for ( i = ifc.ifc_len / sizeof(struct ifreq) ; --i >= 0 ; ifr++ ) + { + int nRet=0; + nRet = osl_getHWAddr(ifr->ifr_name,hard_addr); + if ( nRet > 0 ) + { + memcpy( pAddr , hard_addr, 6 ); + return sal_True; + } + } + + return sal_False; +#endif +} + + +/*****************************************************************************/ +/* osl_getHWAddr */ +/*****************************************************************************/ + +static int osl_getHWAddr(const char *ifname, char* hard_addr) +{ + int ret=0; + struct ifreq ifr; + int so = socket(AF_INET, SOCK_DGRAM, 0); + + strcpy(ifr.ifr_name, ifname); + + /* + * First, get the Interface-FLAGS + */ + + ret=ioctl(so, SIOCGIFFLAGS, &ifr) ; + + if ( ret < 0 ) + { +/* fprintf(stderr, "SIOCGIFFLAGS: %s\n", strerror(errno)); */ + close(so); + return ret; + } + + + /* + * If it is the loopback device, do not consider it any further + */ + + if (ifr.ifr_flags & IFF_LOOPBACK) + { +/* fprintf(stderr, "SIOCGIFFLAGS : is LOOPBACK : %s\n", strerror(errno));*/ + close(so); + return 0; + } + + + /* + * And now, the real thing: the get address + */ + +#ifdef SIOCGIFHWADDR + ret=ioctl(so, SIOCGIFHWADDR, &ifr); +#else + ret=ioctl(so, SIOCGIFADDR, &ifr); +#endif + + if (ret < 0) { +/* fprintf(stderr, "SIOCGIFADDR: %s\n", strerror(errno));*/ + memset(hard_addr, 0, 32); + close(so); + return ret; + } + + close(so); + +#ifdef SIOCGIFHWADDR + memcpy(hard_addr,ifr.ifr_hwaddr.sa_data,8); +#else + memcpy(hard_addr,ifr.ifr_ifru.ifru_addr.sa_data,8); +#endif + + + /* + * Check, if no real, i.e. 00:00:00:00:00:00, address was retrieved. + * The Linux dummy device has this kind of behaviour + */ + + ret=osl_checkAddr(hard_addr); + + if (ret < 0) { +/* fprintf(stderr, "SIOCGIFADDR got '00:00:00:00:00:00'\n"); */ + return ret; + } + +/* fprintf(stderr,"interface : %s -- ",ifname);*/ +/* fprintf(stderr,"HWaddr : %s\n", print_ether(hard_addr));*/ + + return 1; +} + + +/*****************************************************************************/ +/* osl_checkAddr */ +/*****************************************************************************/ + +static int osl_checkAddr(const char* addr) +{ + if (addr[0]==0 && addr[1]==0 && + addr[2]==0 && addr[3]==0 && + addr[4]==0 && addr[5]==0) + { + return -1; + } + return 0; +} + + +#if defined (SPARC) + +#if defined (SOLARIS) && !defined(__sparcv8plus) && !defined(__sparcv9) +#include <sys/types.h> +#include <sys/processor.h> + +/*****************************************************************************/ +/* osl_InitSparcV9 */ +/*****************************************************************************/ + +void osl_InterlockedCountSetV9(sal_Bool bV9); + +/* + * osl_InitSparcV9() should be executed as early as possible. We place it in the + * .init section of sal + */ +#if defined ( __SUNPRO_C ) || defined ( __SUNPRO_CC ) +void osl_InitSparcV9(void); +#pragma init (osl_InitSparcV9) +#elif defined ( __GNUC__ ) +void osl_InitSparcV9(void) __attribute__((constructor)); +#endif + +void osl_InitSparcV9(void) +{ + /* processor_info() identifies SPARCV8 (ie sun4c machines) simply as "sparc" + * and SPARCV9 (ie ultra sparcs, sun4u) as "sparcv9". Since we know that we + * run at least on a SPARCV8 architecture or better, any processor type != "sparc" + * and != "i386" is considered to be SPARCV9 or better + * + * This way we are certain that this will still work if someone names SPARCV10 + * "foobar" + */ + processor_info_t aInfo; + int rc; + + rc = processor_info(0, &aInfo); + + if ( rc != -1 ) { + if ( !strcmp( "sparc", aInfo.pi_processor_type ) /* SPARCV8 */ + || !strcmp( "i386", aInfo.pi_processor_type ) ) /* can't happen, but ... */ + return; + /* we are reasonably certain to be on sparcv9/sparcv8plus or better */ + osl_InterlockedCountSetV9(sal_True); + } +} + +#endif /* SOLARIS */ + +#if defined(NETBSD) && defined(GCC) && !defined(__sparcv9) && !defined(__sparc_v9__) + +#include <sys/param.h> +#include <sys/sysctl.h> +void osl_InitSparcV9(void) __attribute__((constructor)); +void osl_InterlockedCountSetV9(sal_Bool bV9); + +/* Determine which processor we are running on (sparc v8 or v9) + * The approach is very similar to Solaris. + */ + +void osl_InitSparcV9(void) +{ + int mib[2]={CTL_HW,HW_MACHINE}; + char processorname[256]; + size_t len=256; + + /* get the machine name */ + sysctl(mib, 2, processorname, &len, NULL, 0); + if (!strncmp("sparc64",processorname, len)) { + osl_InterlockedCountSetV9(sal_True); + } +} + +#endif /* NETBSD */ + +#endif /* SPARC */ + +#if defined ( LINUX ) && defined ( SPARC ) +#include <sys/utsname.h> +void osl_InitSparcV9(void) __attribute__((constructor)); +void osl_InterlockedCountSetV9(sal_Bool bV9); +/* Determine which processor we are running on (sparc v8 or v9) + * The approach is very similar to Solaris. + */ +void osl_InitSparcV9(void) +{ + struct utsname name; + int rc; + rc = uname(&name); + if ( rc != -1 ) { + if ( !strcmp( "sparc", name.machine )) + return; + osl_InterlockedCountSetV9(sal_True); + } +} +#endif + +#if ( defined(__GNUC__) && (defined(X86) || defined(X86_64)) )\ + || ( defined(SOLARIS) && defined (__SUNPRO_C) && defined(__i386) ) + +/* Safe default */ +int osl_isSingleCPU = 0; + +/* Determine if we are on a multiprocessor/multicore/HT x86/x64 system + * + * The lock prefix for atomic operations in osl_[inc|de]crementInterlockedCount() + * comes with a cost and is especially expensive on pre HT x86 single processor + * systems, where it isn't needed at all. + * + * This should be run as early as possible, thus it's placed in the init section + */ +#if defined(_SC_NPROCESSORS_CONF) /* i.e. MACOSX for Intel doesn't have this */ +#if defined(__GNUC__) +void osl_interlockedCountCheckForSingleCPU(void) __attribute__((constructor)); +#elif defined(__SUNPRO_C) +void osl_interlockedCountCheckForSingleCPU(void); +#pragma init (osl_interlockedCountCheckForSingleCPU) +#endif + +void osl_interlockedCountCheckForSingleCPU(void) +{ + /* In case sysconfig fails be on the safe side, + * consider it a multiprocessor/multicore/HT system */ + if ( sysconf(_SC_NPROCESSORS_CONF) == 1 ) { + osl_isSingleCPU = 1; + } +} +#endif /* defined(_SC_NPROCESSORS_CONF) */ +#endif diff --git a/sal/osl/unx/uunxapi.cxx b/sal/osl/unx/uunxapi.cxx new file mode 100644 index 000000000000..299ea4198fdc --- /dev/null +++ b/sal/osl/unx/uunxapi.cxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + + #ifndef _OSL_UUNXAPI_H_ + #include "uunxapi.h" + #endif + + #ifndef __OSL_SYSTEM_H__ + #include "system.h" + #endif + + #ifndef _LIMITS_H + #include <limits.h> + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + #ifndef _OSL_THREAD_H_ + #include <osl/thread.h> + #endif + + //########################### + inline rtl::OString OUStringToOString(const rtl_uString* s) + { + return rtl::OUStringToOString( + rtl::OUString(const_cast<rtl_uString*>(s)), + osl_getThreadTextEncoding()); + } + + //########################### +#ifdef MACOSX +/* + * Helper function for resolving Mac native alias files (not the same as unix alias files) + * and to return the resolved alias as rtl::OString + */ + inline rtl::OString macxp_resolveAliasAndConvert(const rtl_uString* s) + { + rtl::OString p = OUStringToOString(s); + sal_Char path[PATH_MAX]; + if (p.getLength() < PATH_MAX) + { + strcpy(path, p.getStr()); + macxp_resolveAlias(path, PATH_MAX); + p = rtl::OString(path); + } + return p; + } +#endif /* MACOSX */ + + //########################### + //access_u + int access_u(const rtl_uString* pustrPath, int mode) + { +#ifndef MACOSX // not MACOSX + return access(OUStringToOString(pustrPath).getStr(), mode); +#else + return access(macxp_resolveAliasAndConvert(pustrPath).getStr(), mode); +#endif + } + + //######################### + //realpath_u + sal_Bool realpath_u(const rtl_uString* pustrFileName, rtl_uString** ppustrResolvedName) + { +#ifndef MACOSX // not MACOSX + rtl::OString fn = OUStringToOString(pustrFileName); +#else + rtl::OString fn = macxp_resolveAliasAndConvert(pustrFileName); +#endif + char rp[PATH_MAX]; + bool bRet = realpath(fn.getStr(), rp); + + if (bRet) + { + rtl::OUString resolved = rtl::OStringToOUString( + rtl::OString(static_cast<sal_Char*>(rp)), + osl_getThreadTextEncoding()); + + rtl_uString_assign(ppustrResolvedName, resolved.pData); + } + return bRet; + } + + //######################### + //lstat_u + int lstat_u(const rtl_uString* pustrPath, struct stat* buf) + { +#ifndef MACOSX // not MACOSX + return lstat(OUStringToOString(pustrPath).getStr(), buf); +#else + return lstat(macxp_resolveAliasAndConvert(pustrPath).getStr(), buf); +#endif + } + + //######################### + // @see mkdir + int mkdir_u(const rtl_uString* path, mode_t mode) + { + return mkdir(OUStringToOString(path).getStr(), mode); + } + diff --git a/sal/osl/unx/uunxapi.h b/sal/osl/unx/uunxapi.h new file mode 100644 index 000000000000..9eddc5fe4753 --- /dev/null +++ b/sal/osl/unx/uunxapi.h @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_UUNXAPI_H_ + #define _OSL_UUNXAPI_H_ + + #ifndef _UNISTD_H + #include <unistd.h> + #endif + + #ifndef _STDLIB_H + #include <stdlib.h> + #endif + + #ifndef _TYPES_H + #include <sys/types.h> + #endif + + #ifndef _STAT_H + #include <sys/stat.h> + #endif + + #ifndef _RTL_USTRING_H_ + #include <rtl/ustring.h> + #endif + + + #ifdef __cplusplus + extern "C" + { + #endif + + /* @see access */ + int access_u(const rtl_uString* pustrPath, int mode); + + /*********************************** + @descr + The return value differs from the + realpath function + + @returns sal_True on success else + sal_False + + @see realpath + **********************************/ + sal_Bool realpath_u( + const rtl_uString* pustrFileName, + rtl_uString** ppustrResolvedName); + + /* @see lstat */ + int lstat_u(const rtl_uString* pustrPath, struct stat* buf); + + /* @see mkdir */ + int mkdir_u(const rtl_uString* path, mode_t mode); + + #ifdef __cplusplus + } + #endif + + + #endif /* _OSL_UUNXAPI_H_ */ + diff --git a/sal/osl/unx/uunxapi.hxx b/sal/osl/unx/uunxapi.hxx new file mode 100644 index 000000000000..7f1a9072e8cc --- /dev/null +++ b/sal/osl/unx/uunxapi.hxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_UUNXAPI_HXX_ + #define _OSL_UUNXAPI_HXX_ + + #ifndef _OSL_UUNXAPI_H_ + #include "uunxapi.h" + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + namespace osl + { + + /*********************************** + osl::access + + @see access + **********************************/ + + inline int access(const rtl::OUString& ustrPath, int mode) + { + return access_u(ustrPath.pData, mode); + } + + /*********************************** + osl::realpath + + @descr + The return value differs from the + realpath function + + @returns sal_True on success else + sal_False + + @see realpath + **********************************/ + + inline sal_Bool realpath( + const rtl::OUString& ustrFileName, + rtl::OUString& ustrResolvedName) + { + return realpath_u(ustrFileName.pData, &ustrResolvedName.pData); + } + + + /*********************************** + osl::lstat + + @see lstat + **********************************/ + + inline int lstat(const rtl::OUString& ustrPath, struct stat& buf) + { + return lstat_u(ustrPath.pData, &buf); + } + + /*********************************** + osl::mkdir + @see mkdir + **********************************/ + inline int mkdir(const rtl::OUString& aPath, mode_t aMode) + { + return mkdir_u(aPath.pData, aMode); + } + + } // end namespace osl + + + #endif /* _OSL_UUNXAPI_HXX_ */ + diff --git a/sal/osl/w32/MAKEFILE.MK b/sal/osl/w32/MAKEFILE.MK new file mode 100644 index 000000000000..4749048847b5 --- /dev/null +++ b/sal/osl/w32/MAKEFILE.MK @@ -0,0 +1,118 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=sal +TARGET=cpposl +USE_LDUMP2=TRUE + +PROJECTPCH4DLL=TRUE +PROJECTPCH=cont_pch +PROJECTPCHSOURCE=cont_pch + +MULTITHREAD_OBJ=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# Uncomment the following line if you want to compile with -Wall +# it disables lots of unnecessary warnings comming from the Win32 +# header files (disabling warnings via command line only works with +# MSVC >= 7.x) +# +# CFLAGS+=/wd4668 /wd4711 /wd4201 /wd4710 /wd4619 /wd4514 /wd4820 + +# --- Files -------------------------------------------------------- +.IF "$(CCNUMVER)" >= "001400000000" +CDEFS+=-D_CRT_NON_CONFORMING_SWPRINTFS +.ENDIF + +.IF "$(header)" == "" + +SLOFILES= $(SLO)$/conditn.obj \ + $(SLO)$/diagnose.obj \ + $(SLO)$/dllentry.obj \ + $(SLO)$/semaphor.obj \ + $(SLO)$/socket.obj \ + $(SLO)$/interlck.obj \ + $(SLO)$/nlsupport.obj\ + $(SLO)$/mutex.obj \ + $(SLO)$/thread.obj \ + $(SLO)$/module.obj \ + $(SLO)$/process.obj \ + $(SLO)$/security.obj \ + $(SLO)$/profile.obj \ + $(SLO)$/time.obj \ + $(SLO)$/signal.obj \ + $(SLO)$/pipeimpl.obj \ + $(SLO)$/pipe.obj \ + $(SLO)$/util.obj \ + $(SLO)$/file.obj\ + $(SLO)$/file_dirvol.obj\ + $(SLO)$/file_error.obj\ + $(SLO)$/file_url.obj\ + $(SLO)$/tempfile.obj\ + $(SLO)$/path_helper.obj\ + $(SLO)$/procimpl.obj \ + $(SLO)$/salinit.obj + +OBJFILES= $(OBJ)$/conditn.obj \ + $(OBJ)$/diagnose.obj \ + $(OBJ)$/libutil.obj \ + $(OBJ)$/semaphor.obj \ + $(OBJ)$/socket.obj \ + $(OBJ)$/interlck.obj \ + $(OBJ)$/nlsupport.obj\ + $(OBJ)$/mutex.obj \ + $(OBJ)$/thread.obj \ + $(OBJ)$/module.obj \ + $(OBJ)$/process.obj \ + $(OBJ)$/security.obj \ + $(OBJ)$/profile.obj \ + $(OBJ)$/time.obj \ + $(OBJ)$/signal.obj \ + $(OBJ)$/pipeimpl.obj \ + $(OBJ)$/pipe.obj \ + $(OBJ)$/util.obj \ + $(OBJ)$/file.obj\ + $(OBJ)$/file_dirvol.obj\ + $(OBJ)$/file_error.obj\ + $(OBJ)$/file_url.obj\ + $(OBJ)$/tempfile.obj\ + $(OBJ)$/path_helper.obj\ + $(OBJ)$/procimpl.obj \ + $(OBJ)$/salinit.obj + +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + + diff --git a/sal/osl/w32/conditn.c b/sal/osl/w32/conditn.c new file mode 100644 index 000000000000..1a382af89fcf --- /dev/null +++ b/sal/osl/w32/conditn.c @@ -0,0 +1,141 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/conditn.h> +#include <osl/diagnose.h> +#include <osl/time.h> + +/* + under WIN32, we use the void* oslCondition + as a WIN32 HANDLE (which is also a 32-bit value) +*/ + +/*****************************************************************************/ +/* osl_createCondition */ +/*****************************************************************************/ +oslCondition SAL_CALL osl_createCondition(void) +{ + oslCondition Condition; + + Condition= (oslCondition)CreateEvent(0, /* no security */ + sal_True, /* manual reset */ + sal_False, /* initial state not signaled */ + 0); /* automatic name */ + + return Condition; + +} + +/*****************************************************************************/ +/* osl_destroyCondition */ +/*****************************************************************************/ +void SAL_CALL osl_destroyCondition(oslCondition Condition) +{ + if(Condition) + { + OSL_VERIFY(CloseHandle(Condition)); + } +} + +/*****************************************************************************/ +/* osl_setCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setCondition(oslCondition Condition) +{ + OSL_ASSERT(Condition); + + return (sal_Bool)(SetEvent((HANDLE)Condition) != FALSE); +} + +/*****************************************************************************/ +/* osl_resetCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_resetCondition(oslCondition Condition) +{ + OSL_ASSERT(Condition); + + return (sal_Bool)(ResetEvent((HANDLE)Condition) != FALSE); +} + +/*****************************************************************************/ +/* osl_waitCondition */ +/*****************************************************************************/ +oslConditionResult SAL_CALL osl_waitCondition(oslCondition Condition, + const TimeValue* pTimeout) +{ + DWORD timeout; + + OSL_ASSERT(Condition); + + if (pTimeout) + timeout = pTimeout->Seconds * 1000 + pTimeout->Nanosec / 1000000L; + else + timeout = INFINITE; + + /* It's necessary to process SendMessage calls to the current thread to give other threads + access to COM objects instatiated in this thread */ + + while ( 1 ) + { + /* Only wake up if a SendMessage call to the threads message loop is detected */ + switch( MsgWaitForMultipleObjects( 1, (HANDLE *)(&Condition), FALSE, timeout, QS_SENDMESSAGE ) ) + { + case WAIT_OBJECT_0 + 1: + { + MSG msg; + + /* We Must not dispatch the message. PM_NOREMOVE leaves the message queue untouched + but dispatches SendMessage calls automatically */ + + PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ); + } + break; + + case WAIT_OBJECT_0: + return (osl_cond_result_ok); + + case WAIT_TIMEOUT: + return (osl_cond_result_timeout); + + default: + return (osl_cond_result_error); + } + } +} + +/*****************************************************************************/ +/* osl_checkCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_checkCondition(oslCondition Condition) +{ + OSL_ASSERT(Condition); + + return (sal_Bool)(WaitForSingleObject((HANDLE)Condition, 0) == WAIT_OBJECT_0); +} + diff --git a/sal/osl/w32/diagnose.c b/sal/osl/w32/diagnose.c new file mode 100644 index 000000000000..b46bff44b73c --- /dev/null +++ b/sal/osl/w32/diagnose.c @@ -0,0 +1,188 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#define NO_DEBUG_CRT + +#include <osl/diagnose.h> +#include <osl/thread.h> + +#define NO_DEBUG_CRT + +static pfunc_osl_printDebugMessage _pPrintDebugMessage = NULL; +static pfunc_osl_printDetailedDebugMessage _pPrintDetailedDebugMessage = NULL; + +pfunc_osl_printDebugMessage SAL_CALL osl_setDebugMessageFunc( pfunc_osl_printDebugMessage pNewFunc ) +{ + pfunc_osl_printDebugMessage pOldFunc = _pPrintDebugMessage; + _pPrintDebugMessage = pNewFunc; + + return pOldFunc; +} + +pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc( pfunc_osl_printDetailedDebugMessage pNewFunc ) +{ + pfunc_osl_printDetailedDebugMessage pOldFunc = _pPrintDetailedDebugMessage; + _pPrintDetailedDebugMessage = pNewFunc; + return pOldFunc; +} + +/* + Trace output +*/ + +void SAL_CALL osl_breakDebug(void) +{ + DebugBreak(); +} + + + +/* Uncomment this define to get profiling time output */ +/* #define OSL_PROFILING */ +/* comment this define to stop output thread identifier*/ +#define OSL_TRACE_THREAD 1 +void SAL_CALL osl_trace(const sal_Char* lpszFormat, ...) +{ + va_list args; + int written = 0; + + va_start(args, lpszFormat); + +#if defined(OSL_PROFILING) + fprintf(stderr, "time : %06lu : ", osl_getGlobalTimer() ); +#else +#if defined(OSL_TRACE_THREAD) + fprintf(stderr,"Thread: %6d :",osl_getThreadIdentifier(NULL)); +#else + fprintf(stderr,"Trace Message : "); +#endif +#endif + + if ( IsDebuggerPresent() ) + { + sal_Char szMessage[512]; + written = _vsnprintf( szMessage, sizeof(szMessage) - 2, lpszFormat, args ); + if ( written == -1 ) + written = sizeof(szMessage) - 2; + szMessage[ written++ ] = '\n'; + szMessage[ written ] = 0; + OutputDebugString( szMessage ); + } + + vfprintf(stderr,lpszFormat, args); + + fprintf(stderr,"\n"); + + fflush(stderr); + + va_end(args); +} + +sal_Bool SAL_CALL osl_assertFailedLine(const sal_Char* pszFileName, sal_Int32 nLine, const sal_Char* pszMessage) +{ +#ifndef NO_DEBUG_CRT + return (_CrtDbgReport(_CRT_ASSERT, pszFileName, nLine, NULL, pszMessage)); +#else + HWND hWndParent; + UINT nFlags; + int nCode; + + /* get app name or NULL if unknown (don't call assert) */ + LPCSTR lpszAppName = "Error"; + sal_Char szMessage[512]; + + /* format message into buffer */ + szMessage[sizeof(szMessage)-1] = '\0'; /* zero terminate always */ + _snprintf(szMessage, sizeof(szMessage)-1, "%s: File %hs, Line %d\n:%s\n", + lpszAppName, pszFileName, nLine, pszMessage); + + OutputDebugString(szMessage); + + if ( _pPrintDetailedDebugMessage ) + _pPrintDetailedDebugMessage( pszFileName, nLine, pszMessage ); + else if ( _pPrintDebugMessage ) + _pPrintDebugMessage( szMessage ); + else if ( !getenv( "DISABLE_SAL_DBGBOX" ) ) + { + TCHAR szBoxMessage[1024]; + + /* active popup window for the current thread */ + hWndParent = GetActiveWindow(); + if (hWndParent != NULL) + hWndParent = GetLastActivePopup(hWndParent); + + /* set message box flags */ + nFlags = MB_TASKMODAL | MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_SETFOREGROUND; + if (hWndParent == NULL) + nFlags |= MB_SERVICE_NOTIFICATION; + + /* display the assert */ + + szBoxMessage[sizeof(szBoxMessage)-1] = 0; + _snprintf(szBoxMessage, sizeof(szBoxMessage)-1, "%s\n( Yes=Abort / No=Ignore / Cancel=Debugger )", + szMessage); + + nCode = MessageBox(hWndParent, szBoxMessage, "Assertion Failed!", nFlags); + + if (nCode == IDYES) + FatalExit(-1); + + if (nCode == IDNO) + return sal_False; /* ignore */ + + if (nCode == IDCANCEL) + return sal_True; /* will cause oslDebugBreak */ + } +#endif /* NO_DEBUG_CRT */ + return sal_False; /* not shure, not care */ +} + +sal_Int32 SAL_CALL osl_reportError(sal_uInt32 nType, const sal_Char* pszMessage) +{ + UINT nFlags; + int nDisposition; + + // active popup window for the current thread + HWND hWndParent = GetActiveWindow(); + if (hWndParent != NULL) + hWndParent = GetLastActivePopup(hWndParent); + + nType = nType; /* avoid warnings */ + + /* set message box flags */ + nFlags = MB_TASKMODAL | MB_ICONERROR | MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_SETFOREGROUND; + if (hWndParent == NULL) + nFlags |= MB_SERVICE_NOTIFICATION; + + // display the assert + nDisposition = MessageBox(hWndParent, pszMessage, "Exception!", nFlags); + + return nDisposition; +} + diff --git a/sal/osl/w32/dllentry.c b/sal/osl/w32/dllentry.c new file mode 100644 index 000000000000..b6a21d6c2724 --- /dev/null +++ b/sal/osl/w32/dllentry.c @@ -0,0 +1,370 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(push,1) /* disable warnings within system headers */ +#endif +#include <windows.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#include <tlhelp32.h> +#include <systools/win32/uwinapi.h> +#include <winsock.h> +#include <osl/diagnose.h> +#include <sal/types.h> +#include <float.h> + +#include <osl/diagnose.h> +#include <osl/mutex.h> +#include <sal/types.h> + +//------------------------------------------------------------------------------ +// externals +//------------------------------------------------------------------------------ + +extern DWORD g_dwTLSTextEncodingIndex; +extern void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void); +extern CRITICAL_SECTION g_ThreadKeyListCS; +extern oslMutex g_Mutex; +extern oslMutex g_CurrentDirectoryMutex; + +extern void rtl_locale_fini (void); +extern void rtl_memory_fini (void); +extern void rtl_cache_fini (void); +extern void rtl_arena_fini (void); + +#ifdef __MINGW32__ + +typedef void (*func_ptr) (void); +extern func_ptr __CTOR_LIST__[]; +extern func_ptr __DTOR_LIST__[]; + +static void do_startup(void); +static void do_cleanup(void); + +#else + +/* +This is needed because DllMain is called after static constructors. A DLL's +startup and shutdown sequence looks like this: + +_pRawDllMain() +_CRT_INIT() +DllMain() +.... +DllMain() +_CRT_INIT() +_pRawDllMain() + +*/ + +static BOOL WINAPI _RawDllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ); +extern BOOL (WINAPI *_pRawDllMain)(HANDLE, DWORD, LPVOID) = _RawDllMain; + +#endif + +//------------------------------------------------------------------------------ +// globales +//------------------------------------------------------------------------------ + +DWORD g_dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; // remember plattform + +//------------------------------------------------------------------------------ +// DllMain +//------------------------------------------------------------------------------ +#ifdef _M_IX86 +int osl_isSingleCPU = 0; +#endif + +#ifdef __MINGW32__ + +void +__do_global_dtors (void) +{ + static func_ptr *p = __DTOR_LIST__ + 1; + + /* + * Call each destructor in the destructor list until a null pointer + * is encountered. + */ + while (*p) + { + (*(p)) (); + p++; + } +} + +void +__do_global_ctors (void) +{ + unsigned long nptrs = (unsigned long) __CTOR_LIST__[0]; + unsigned i; + + /* + * If the first entry in the constructor list is -1 then the list + * is terminated with a null entry. Otherwise the first entry was + * the number of pointers in the list. + */ + if (nptrs == -1) + { + for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++) + ; + } + + /* + * Go through the list backwards calling constructors. + */ + for (i = nptrs; i >= 1; i--) + { + __CTOR_LIST__[i] (); + } + + /* + * Register the destructors for processing on exit. + */ + atexit (__do_global_dtors); +} + +static int initialized = 0; + +void +__main (void) +{ + if (!initialized) + { + initialized = 1; + do_startup(); + __do_global_ctors (); + } +} + +static void do_startup( void ) +{ +#else +static BOOL WINAPI _RawDllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) +{ + (void)hinstDLL; /* avoid warnings */ + (void)lpvReserved; /* avoid warnings */ + + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + { +#endif + OSVERSIONINFO aInfo; + +#ifdef _M_IX86 + SYSTEM_INFO SystemInfo; + + GetSystemInfo(&SystemInfo); + + /* Determine if we are on a multiprocessor/multicore/HT x86/x64 system + * + * The lock prefix for atomic operations in osl_[inc|de]crementInterlockedCount() + * comes with a cost and is especially expensive on pre HT x86 single processor + * systems, where it isn't needed at all. + */ + if ( SystemInfo.dwNumberOfProcessors == 1 ) { + osl_isSingleCPU = 1; + } +#endif + /* Suppress file error messages from system like "Floppy A: not inserted" */ + SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS ); + + /* initialize global mutex */ + g_Mutex = osl_createMutex(); + + /* initialize "current directory" mutex */ + g_CurrentDirectoryMutex = osl_createMutex(); + + + /* initialize Win9x unicode functions */ + aInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); + + if ( GetVersionEx(&aInfo) ) + g_dwPlatformId = aInfo.dwPlatformId; + + g_dwTLSTextEncodingIndex = TlsAlloc(); + InitializeCriticalSection( &g_ThreadKeyListCS ); + + //We disable floating point exceptions. This is the usual state at program startup + //but on Windows 98 and ME this is not always the case. + _control87(_MCW_EM, _MCW_EM); +#ifdef __MINGW32__ + atexit(do_cleanup); +} + +void do_cleanup( void ) +{ +#else + break; + } + + case DLL_PROCESS_DETACH: +#endif + + WSACleanup( ); + + TlsFree( g_dwTLSTextEncodingIndex ); + DeleteCriticalSection( &g_ThreadKeyListCS ); + + osl_destroyMutex( g_Mutex ); + + osl_destroyMutex( g_CurrentDirectoryMutex ); + +#ifndef __MINGW32__ + + /* + + On a product build memory management finalization might + cause a crash without assertion (assertions off) if heap is + corrupted. But a crash report won't help here because at + this point all other threads have been terminated and only + ntdll is on the stack. No chance to find the reason for the + corrupted heap if so. + + So annoying the user with a crash report is completly useless. + + */ + +#ifndef DBG_UTIL + __try +#endif + { + /* cleanup locale hashtable */ + rtl_locale_fini(); + + /* finalize memory management */ + rtl_memory_fini(); + rtl_cache_fini(); + rtl_arena_fini(); + } +#ifndef DBG_UTIL + __except( EXCEPTION_EXECUTE_HANDLER ) + { + } +#endif + break; + } + + return TRUE; +#endif +} + +static DWORD GetParentProcessId() +{ + DWORD dwParentProcessId = 0; + HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); + + if ( IsValidHandle( hSnapshot ) ) + { + PROCESSENTRY32 pe; + BOOL fSuccess; + + ZeroMemory( &pe, sizeof(pe) ); + pe.dwSize = sizeof(pe); + fSuccess = Process32First( hSnapshot, &pe ); + + while( fSuccess ) + { + if ( GetCurrentProcessId() == pe.th32ProcessID ) + { + dwParentProcessId = pe.th32ParentProcessID; + break; + } + + fSuccess = Process32Next( hSnapshot, &pe ); + } + + CloseHandle( hSnapshot ); + } + + return dwParentProcessId; +} + +static DWORD WINAPI ParentMonitorThreadProc( LPVOID lpParam ) +{ + DWORD dwParentProcessId = (DWORD)lpParam; + + HANDLE hParentProcess = OpenProcess( SYNCHRONIZE, FALSE, dwParentProcessId ); + if ( IsValidHandle( hParentProcess ) ) + { + if ( WAIT_OBJECT_0 == WaitForSingleObject( hParentProcess, INFINITE ) ) + { + TerminateProcess( GetCurrentProcess(), 0 ); + } + CloseHandle( hParentProcess ); + } + return 0; +} + +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) +{ + (void)hinstDLL; /* avoid warning */ + (void)lpvReserved; /* avoid warning */ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + { + TCHAR szBuffer[64]; + + // This code will attach the process to it's parent process + // if the parent process had set the environment variable. + // The corresponding code (setting the environment variable) + // is is desktop/win32/source/officeloader.cxx + + + DWORD dwResult = GetEnvironmentVariable( "ATTACHED_PARENT_PROCESSID", szBuffer, sizeof(szBuffer) ); + + if ( dwResult && dwResult < sizeof(szBuffer) ) + { + DWORD dwThreadId = 0; + + DWORD dwParentProcessId = (DWORD)atol( szBuffer ); + + if ( dwParentProcessId && GetParentProcessId() == dwParentProcessId ) + { + // No error check, it works or it does not + // Thread should only be started for headless mode, see desktop/win32/source/officeloader.cxx + CreateThread( NULL, 0, ParentMonitorThreadProc, (LPVOID)dwParentProcessId, 0, &dwThreadId ); // + } + } + + return TRUE; + } + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + _osl_callThreadKeyCallbackOnThreadDetach( ); + break; + } + + return TRUE; +} diff --git a/sal/osl/w32/file.cxx b/sal/osl/w32/file.cxx new file mode 100644 index 000000000000..7728189387cd --- /dev/null +++ b/sal/osl/w32/file.cxx @@ -0,0 +1,1194 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#define UNICODE +#define _UNICODE +#define _WIN32_WINNT 0x0500 +#include "systools/win32/uwinapi.h" + +#include "osl/file.hxx" + +#include "file_url.h" +#include "file_error.h" + +#include "osl/diagnose.h" +#include "rtl/alloc.h" +#include "rtl/byteseq.h" +#include "rtl/ustring.hxx" + +#include <stdio.h> +#include <tchar.h> + +#ifdef __MINGW32__ +#include <wchar.h> +#include <ctype.h> +#endif + +#include <algorithm> +#include <limits> + +#ifdef max /* conflict w/ std::numeric_limits<T>::max() */ +#undef max +#endif +#ifdef min +#undef min +#endif + +//################################################################## +// File handle implementation +//################################################################## +struct FileHandle_Impl +{ + CRITICAL_SECTION m_mutex; + HANDLE m_hFile; + + /** State + */ + enum StateBits + { + STATE_SEEKABLE = 1, /* open() sets, iff regular file */ + STATE_READABLE = 2, /* open() sets, read() requires */ + STATE_WRITEABLE = 4, /* open() sets, write() requires */ + STATE_MODIFIED = 8 /* write() sets, flush() resets */ + }; + int m_state; + + sal_uInt64 m_size; /* file size */ + LONGLONG m_offset; /* physical offset from begin of file */ + LONGLONG m_filepos; /* logical offset from begin of file */ + + LONGLONG 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 (HANDLE hFile); + ~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 ( + LONGLONG nOffset, + void * pBuffer, + DWORD nBytesRequested, + sal_uInt64 * pBytesRead); + + oslFileError writeAt ( + LONGLONG nOffset, + void const * pBuffer, + DWORD nBytesToWrite, + sal_uInt64 * pBytesWritten); + + oslFileError readFileAt ( + LONGLONG nOffset, + void * pBuffer, + sal_uInt64 uBytesRequested, + sal_uInt64 * pBytesRead); + + oslFileError writeFileAt ( + LONGLONG nOffset, + void const * pBuffer, + sal_uInt64 uBytesToWrite, + 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(); + }; + + /** Guard. + */ + class Guard + { + LPCRITICAL_SECTION m_mutex; + + public: + explicit Guard(LPCRITICAL_SECTION pMutex); + ~Guard(); + }; +}; + +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::Guard::Guard(LPCRITICAL_SECTION pMutex) + : m_mutex (pMutex) +{ + OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer."); + ::EnterCriticalSection (m_mutex); +} +FileHandle_Impl::Guard::~Guard() +{ + OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer."); + ::LeaveCriticalSection (m_mutex); +} + +FileHandle_Impl::FileHandle_Impl(HANDLE hFile) + : m_hFile (hFile), + m_state (STATE_READABLE | STATE_WRITEABLE), + m_size (0), + m_offset (0), + m_filepos (0), + m_bufptr (-1), + m_buflen (0), + m_bufsiz (0), + m_buffer (0) +{ + ::InitializeCriticalSection (&m_mutex); + 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; + ::DeleteCriticalSection (&m_mutex); +} + +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() +{ + SYSTEM_INFO info; + ::GetSystemInfo (&info); + return sal::static_int_cast< SIZE_T >(info.dwPageSize); +} + +sal_uInt64 FileHandle_Impl::getPos() const +{ + return sal::static_int_cast< sal_uInt64 >(m_filepos); +} + +oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos) +{ + m_filepos = 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) +{ + LARGE_INTEGER nDstPos; nDstPos.QuadPart = sal::static_int_cast< LONGLONG >(uSize); + if (!::SetFilePointerEx(m_hFile, nDstPos, 0, FILE_BEGIN)) + return oslTranslateFileError( GetLastError() ); + + if (!::SetEndOfFile(m_hFile)) + return oslTranslateFileError( GetLastError() ); + m_size = uSize; + + nDstPos.QuadPart = m_offset; + if (!::SetFilePointerEx(m_hFile, nDstPos, 0, FILE_BEGIN)) + return oslTranslateFileError( GetLastError() ); + + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::readAt ( + LONGLONG nOffset, + void * pBuffer, + DWORD 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) + { + LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset; + if (!::SetFilePointerEx(m_hFile, liOffset, 0, FILE_BEGIN)) + return oslTranslateFileError( GetLastError() ); + m_offset = nOffset; + } + + DWORD dwDone = 0; + if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, 0)) + return oslTranslateFileError( GetLastError() ); + m_offset += dwDone; + + *pBytesRead = dwDone; + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::writeAt ( + LONGLONG nOffset, + void const * pBuffer, + DWORD 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) + { + LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset; + if (!::SetFilePointerEx (m_hFile, liOffset, 0, FILE_BEGIN)) + return oslTranslateFileError( GetLastError() ); + m_offset = nOffset; + } + + DWORD dwDone = 0; + if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, 0)) + return oslTranslateFileError( GetLastError() ); + m_offset += dwDone; + + m_size = std::max(m_size, sal::static_int_cast< sal_uInt64 >(m_offset)); + + *pBytesWritten = dwDone; + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::readFileAt ( + LONGLONG nOffset, + void * pBuffer, + sal_uInt64 uBytesRequested, + sal_uInt64 * pBytesRead) +{ + static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max(); + if (g_limit_dword < uBytesRequested) + return osl_File_E_OVERFLOW; + DWORD nBytesRequested = sal::static_int_cast< DWORD >(uBytesRequested); + + if (0 == (m_state & STATE_SEEKABLE)) + { + // not seekable (pipe) + DWORD dwDone = 0; + if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, 0)) + return oslTranslateFileError( GetLastError() ); + *pBytesRead = dwDone; + 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; ) + { + LONGLONG 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); + m_bufptr = -1, m_buflen = 0; + + 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 -= sal::static_int_cast< DWORD >(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 = sal::static_int_cast< SIZE_T >(uDone); + } + if (bufpos >= m_buflen) + { + // end of file + return osl_File_E_None; + } + + SIZE_T const bytes = std::min(m_buflen - bufpos, nBytesRequested); + memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes); + nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes; + } + return osl_File_E_None; + } +} + +oslFileError FileHandle_Impl::writeFileAt ( + LONGLONG nOffset, + void const * pBuffer, + sal_uInt64 uBytesToWrite, + sal_uInt64 * pBytesWritten) +{ + static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max(); + if (g_limit_dword < uBytesToWrite) + return osl_File_E_OVERFLOW; + DWORD nBytesToWrite = sal::static_int_cast< DWORD >(uBytesToWrite); + + if (0 == (m_state & STATE_SEEKABLE)) + { + // not seekable (pipe) + DWORD dwDone = 0; + if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, 0)) + return oslTranslateFileError( GetLastError() ); + *pBytesWritten = dwDone; + 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; ) + { + LONGLONG 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); + m_bufptr = -1, m_buflen = 0; + + if (nBytesToWrite >= m_bufsiz) + { + // buffer too 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 -= sal::static_int_cast< DWORD >(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 = sal::static_int_cast< SIZE_T >(uDone); + } + + SIZE_T const bytes = std::min(m_bufsiz - bufpos, nBytesToWrite); + 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); +} + +//################################################################## +// File I/O functions +//################################################################## + +extern "C" oslFileHandle +SAL_CALL osl_createFileHandleFromOSHandle ( + HANDLE hFile, + sal_uInt32 uFlags) +{ + if ( !IsValidHandle(hFile) ) + return 0; // EINVAL + + FileHandle_Impl * pImpl = new FileHandle_Impl(hFile); + if (pImpl == 0) + { + // cleanup and fail + (void) ::CloseHandle(hFile); + return 0; // ENOMEM + } + + /* check for regular file */ + if (FILE_TYPE_DISK == GetFileType(hFile)) + { + /* mark seekable */ + pImpl->m_state |= FileHandle_Impl::STATE_SEEKABLE; + + /* init current size */ + LARGE_INTEGER uSize = { 0, 0 }; + (void) ::GetFileSizeEx(hFile, &uSize); + pImpl->m_size = (sal::static_int_cast<sal_uInt64>(uSize.HighPart) << 32) + uSize.LowPart; + } + + if (!(uFlags & osl_File_OpenFlag_Read)) + pImpl->m_state &= ~FileHandle_Impl::STATE_READABLE; + if (!(uFlags & osl_File_OpenFlag_Write)) + pImpl->m_state &= ~FileHandle_Impl::STATE_WRITEABLE; + + OSL_POSTCOND( + (uFlags & osl_File_OpenFlag_Read) || (uFlags & osl_File_OpenFlag_Write), + "osl_createFileHandleFromOSHandle(): missing read/write access flags"); + return (oslFileHandle)(pImpl); +} + +//############################################# +oslFileError +SAL_CALL osl_openFile( + rtl_uString * strPath, + oslFileHandle * pHandle, + sal_uInt32 uFlags ) +{ + rtl_uString * strSysPath = 0; + oslFileError result = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + if (result != osl_File_E_None) + return (result); + + DWORD dwAccess = GENERIC_READ, dwShare = FILE_SHARE_READ, dwCreation = 0, dwAttributes = 0; + + if ( uFlags & osl_File_OpenFlag_Write ) + dwAccess |= GENERIC_WRITE; + else + dwShare |= FILE_SHARE_WRITE; + + if ( uFlags & osl_File_OpenFlag_NoLock ) + dwShare |= FILE_SHARE_WRITE; + + if ( uFlags & osl_File_OpenFlag_Create ) + dwCreation |= CREATE_NEW; + else + dwCreation |= OPEN_EXISTING; + + HANDLE hFile = CreateFileW( + reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strSysPath )), + dwAccess, dwShare, NULL, dwCreation, dwAttributes, NULL ); + + // @@@ ERROR HANDLING @@@ + if ( !IsValidHandle( hFile ) ) + result = oslTranslateFileError( GetLastError() ); + + *pHandle = osl_createFileHandleFromOSHandle (hFile, uFlags | osl_File_OpenFlag_Read); + + rtl_uString_release( strSysPath ); + return (result); +} + +//############################################# +oslFileError +SAL_CALL osl_syncFile(oslFileHandle Handle) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + return result; + + if (!FlushFileBuffers(pImpl->m_hFile)) + return oslTranslateFileError(GetLastError()); + + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_closeFile(oslFileHandle Handle) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile)) + return osl_File_E_INVAL; + + ::EnterCriticalSection (&(pImpl->m_mutex)); + + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + { + /* ignore double failure */ + (void)::CloseHandle(pImpl->m_hFile); + } + else if (!::CloseHandle(pImpl->m_hFile)) + { + /* translate error code */ + result = oslTranslateFileError( GetLastError() ); + } + + ::LeaveCriticalSection (&(pImpl->m_mutex)); + delete pImpl; + return (result); +} + +//############################################# +oslFileError +SAL_CALL osl_mapFile( + oslFileHandle Handle, + void** ppAddr, + sal_uInt64 uLength, + sal_uInt64 uOffset, + sal_uInt32 uFlags) +{ + struct FileMapping + { + HANDLE m_handle; + + explicit FileMapping (HANDLE hMap) + : m_handle (hMap) + {} + + ~FileMapping() + { + (void)::CloseHandle(m_handle); + } + }; + + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == ppAddr)) + return osl_File_E_INVAL; + *ppAddr = 0; + + static SIZE_T const nLimit = std::numeric_limits< SIZE_T >::max(); + if (uLength > nLimit) + return osl_File_E_OVERFLOW; + SIZE_T const nLength = sal::static_int_cast< SIZE_T >(uLength); + + OSVERSIONINFO osinfo; + osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + (void)::GetVersionEx(&osinfo); + + if (VER_PLATFORM_WIN32_NT != osinfo.dwPlatformId) + return osl_File_E_NOSYS; // Unsupported + + FileMapping aMap( ::CreateFileMapping (pImpl->m_hFile, NULL, SEC_COMMIT | PAGE_READONLY, 0, 0, NULL) ); + if (!IsValidHandle(aMap.m_handle)) + return oslTranslateFileError( GetLastError() ); + + DWORD const dwOffsetHi = sal::static_int_cast<DWORD>(uOffset >> 32); + DWORD const dwOffsetLo = sal::static_int_cast<DWORD>(uOffset & 0xFFFFFFFF); + + *ppAddr = ::MapViewOfFile( aMap.m_handle, FILE_MAP_READ, dwOffsetHi, dwOffsetLo, nLength ); + if (0 == *ppAddr) + return oslTranslateFileError( GetLastError() ); + + if (uFlags & osl_File_MapFlag_RandomAccess) + { + // Determine memory pagesize. + SYSTEM_INFO info; + ::GetSystemInfo( &info ); + DWORD const dwPageSize = info.dwPageSize; + + /* + * Pagein, touching first byte of each memory page. + * Note: volatile disables optimizing the loop away. + */ + BYTE * pData (reinterpret_cast<BYTE*>(*ppAddr)); + SIZE_T nSize (nLength); + + volatile BYTE c = 0; + while (nSize > dwPageSize) + { + c ^= pData[0]; + pData += dwPageSize; + nSize -= dwPageSize; + } + if (nSize > 0) + { + c ^= pData[0]; + pData += nSize; + nSize -= nSize; + } + } + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 /* uLength */) +{ + if (0 == pAddr) + return osl_File_E_INVAL; + + if (!::UnmapViewOfFile (pAddr)) + return oslTranslateFileError( GetLastError() ); + + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_readLine( + oslFileHandle Handle, + sal_Sequence ** ppSequence) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == ppSequence)) + return osl_File_E_INVAL; + sal_uInt64 uBytesRead = 0; + + // read at current filepos; filepos += uBytesRead; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->readLineAt ( + pImpl->m_filepos, ppSequence, &uBytesRead); + if (result == osl_File_E_None) + pImpl->m_filepos += uBytesRead; + return (result); +} + +//############################################# +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) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesRead)) + return osl_File_E_INVAL; + + // read at current filepos; filepos += *pBytesRead; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->readFileAt ( + pImpl->m_filepos, pBuffer, uBytesRequested, pBytesRead); + if (result == osl_File_E_None) + pImpl->m_filepos += *pBytesRead; + return (result); +} + +//############################################# +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) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesWritten)) + return osl_File_E_INVAL; + + // write at current filepos; filepos += *pBytesWritten; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->writeFileAt ( + pImpl->m_filepos, pBuffer, uBytesToWrite, pBytesWritten); + if (result == osl_File_E_None) + pImpl->m_filepos += *pBytesWritten; + return (result); +} + +//############################################# +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) || !IsValidHandle(pImpl->m_hFile) || (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_longlong = std::numeric_limits< LONGLONG >::max(); + if (g_limit_longlong < uOffset) + return osl_File_E_OVERFLOW; + LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset); + + // read at specified fileptr + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + return pImpl->readFileAt (nOffset, pBuffer, uBytesRequested, pBytesRead); +} + +//############################################# +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) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesWritten)) + 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_longlong = std::numeric_limits< LONGLONG >::max(); + if (g_limit_longlong < uOffset) + return osl_File_E_OVERFLOW; + LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset); + + // write at specified fileptr + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + return pImpl->writeFileAt (nOffset, pBuffer, uBytesToWrite, pBytesWritten); +} + +//############################################# +oslFileError +SAL_CALL osl_isEndOfFile (oslFileHandle Handle, sal_Bool *pIsEOF) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pIsEOF)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pIsEOF = (pImpl->getPos() == pImpl->getSize()); + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64 *pPos) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pPos)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pPos = pImpl->getPos(); + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile)) + return osl_File_E_INVAL; + + static sal_Int64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max(); + if (g_limit_longlong < uOffset) + return osl_File_E_OVERFLOW; + LONGLONG nPos = 0, nOffset = sal::static_int_cast< LONGLONG >(uOffset); + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + switch (uHow) + { + case osl_Pos_Absolut: + if (0 > nOffset) + return osl_File_E_INVAL; + break; + + case osl_Pos_Current: + nPos = sal::static_int_cast< LONGLONG >(pImpl->getPos()); + if ((0 > nOffset) && (-1*nOffset > nPos)) + return osl_File_E_INVAL; + if (g_limit_longlong < nPos + nOffset) + return osl_File_E_OVERFLOW; + break; + + case osl_Pos_End: + nPos = sal::static_int_cast< LONGLONG >(pImpl->getSize()); + if ((0 > nOffset) && (-1*nOffset > nPos)) + return osl_File_E_INVAL; + if (g_limit_longlong < nPos + nOffset) + return osl_File_E_OVERFLOW; + break; + + default: + return osl_File_E_INVAL; + } + + return pImpl->setPos (nPos + nOffset); +} + +//############################################# +oslFileError +SAL_CALL osl_getFileSize (oslFileHandle Handle, sal_uInt64 *pSize) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pSize)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pSize = pImpl->getSize(); + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_setFileSize (oslFileHandle Handle, sal_uInt64 uSize) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile)) + 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_longlong = std::numeric_limits< LONGLONG >::max(); + if (g_limit_longlong < uSize) + return osl_File_E_OVERFLOW; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + return (result); + pImpl->m_bufptr = -1, pImpl->m_buflen = 0; + + return pImpl->setSize (uSize); +} + +//################################################################## +// File handling functions +//################################################################## + +//############################################# +oslFileError SAL_CALL osl_removeFile( rtl_uString* strPath ) +{ + rtl_uString *strSysPath = NULL; + oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + + if ( osl_File_E_None == error ) + { + if ( DeleteFile( reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )) ) ) + error = osl_File_E_None; + else + error = oslTranslateFileError( GetLastError() ); + + rtl_uString_release( strSysPath ); + } + return error; +} + +//############################################# +#define osl_File_CopyRecursive 0x0001 +#define osl_File_CopyOverwrite 0x0002 + +oslFileError SAL_CALL osl_copyFile( rtl_uString* strPath, rtl_uString *strDestPath ) +{ + rtl_uString *strSysPath = NULL, *strSysDestPath = NULL; + oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + + if ( osl_File_E_None == error ) + error = _osl_getSystemPathFromFileURL( strDestPath, &strSysDestPath, sal_False ); + + if ( osl_File_E_None == error ) + { + LPCTSTR src = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )); + LPCTSTR dst = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysDestPath )); + + if ( CopyFile( src, dst, FALSE ) ) + error = osl_File_E_None; + else + error = oslTranslateFileError( GetLastError() ); + } + + if ( strSysPath ) + rtl_uString_release( strSysPath ); + if ( strSysDestPath ) + rtl_uString_release( strSysDestPath ); + + return error; +} + +//############################################# +oslFileError SAL_CALL osl_moveFile( rtl_uString* strPath, rtl_uString *strDestPath ) +{ + rtl_uString *strSysPath = NULL, *strSysDestPath = NULL; + oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + + if ( osl_File_E_None == error ) + error = _osl_getSystemPathFromFileURL( strDestPath, &strSysDestPath, sal_False ); + + if ( osl_File_E_None == error ) + { + LPCTSTR src = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )); + LPCTSTR dst = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysDestPath )); + + if ( MoveFileEx( src, dst, MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING ) ) + error = osl_File_E_None; + else + error = oslTranslateFileError( GetLastError() ); + } + + if ( strSysPath ) + rtl_uString_release( strSysPath ); + if ( strSysDestPath ) + rtl_uString_release( strSysDestPath ); + + return error; +} diff --git a/sal/osl/w32/file_dirvol.cxx b/sal/osl/w32/file_dirvol.cxx new file mode 100644 index 000000000000..09bdec7988c3 --- /dev/null +++ b/sal/osl/w32/file_dirvol.cxx @@ -0,0 +1,1867 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define UNICODE +#define _UNICODE +#define _WIN32_WINNT_0x0500 +#include "systools/win32/uwinapi.h" + +#include "osl/file.h" + +#include "file_url.h" +#include "file_error.h" + +#include "path_helper.hxx" + +#include "osl/diagnose.h" +#include "osl/time.h" +#include "rtl/alloc.h" +#include "rtl/ustring.hxx" + +#include <tchar.h> +#ifdef __MINGW32__ +#include <ctype.h> +#endif + +//##################################################### +#define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0]))) + +static const wchar_t UNC_PREFIX[] = L"\\\\"; +static const wchar_t BACKSLASH = '\\'; +static const wchar_t SLASH = '/'; + +//##################################################### +extern "C" BOOL TimeValueToFileTime(const TimeValue *cpTimeVal, FILETIME *pFTime) +{ + SYSTEMTIME BaseSysTime; + FILETIME BaseFileTime; + FILETIME FTime; + __int64 localTime; + BOOL fSuccess = FALSE; + + BaseSysTime.wYear = 1970; + BaseSysTime.wMonth = 1; + BaseSysTime.wDayOfWeek = 0; + BaseSysTime.wDay = 1; + BaseSysTime.wHour = 0; + BaseSysTime.wMinute = 0; + BaseSysTime.wSecond = 0; + BaseSysTime.wMilliseconds = 0; + + if (cpTimeVal==NULL) + return fSuccess; + + if ( SystemTimeToFileTime(&BaseSysTime, &BaseFileTime) ) + { + __int64 timeValue; + localTime=cpTimeVal->Seconds*(__int64)10000000+cpTimeVal->Nanosec/100; + *(__int64 *)&FTime=localTime; + fSuccess = 0 <= (timeValue= *((__int64 *)&BaseFileTime) + *((__int64 *) &FTime)); + if (fSuccess) + *(__int64 *)pFTime=timeValue; + } + return fSuccess; +} + +//##################################################### +extern "C" BOOL FileTimeToTimeValue(const FILETIME *cpFTime, TimeValue *pTimeVal) +{ + SYSTEMTIME BaseSysTime; + FILETIME BaseFileTime; + BOOL fSuccess = FALSE; /* Assume failure */ + + BaseSysTime.wYear = 1970; + BaseSysTime.wMonth = 1; + BaseSysTime.wDayOfWeek = 0; + BaseSysTime.wDay = 1; + BaseSysTime.wHour = 0; + BaseSysTime.wMinute = 0; + BaseSysTime.wSecond = 0; + BaseSysTime.wMilliseconds = 0; + + if ( SystemTimeToFileTime(&BaseSysTime, &BaseFileTime) ) + { + __int64 Value; + + fSuccess = 0 <= (Value = *((__int64 *)cpFTime) - *((__int64 *)&BaseFileTime)); + + if ( fSuccess ) + { + pTimeVal->Seconds = (unsigned long) (Value / 10000000L); + pTimeVal->Nanosec = (unsigned long)((Value % 10000000L) * 100); + } + } + return fSuccess; +} + +//##################################################### +namespace /* private */ +{ + //##################################################### + struct Component + { + Component() : + begin_(0), end_(0) + {} + + bool isPresent() const + { return (static_cast<sal_IntPtr>(end_ - begin_) > 0); } + + const sal_Unicode* begin_; + const sal_Unicode* end_; + }; + + //##################################################### + struct UNCComponents + { + Component server_; + Component share_; + Component resource_; + }; + + //##################################################### + inline bool is_UNC_path(const sal_Unicode* path) + { return (0 == wcsncmp(UNC_PREFIX, reinterpret_cast<LPCWSTR>(path), ELEMENTS_OF_ARRAY(UNC_PREFIX) - 1)); } + + //##################################################### + inline bool is_UNC_path(const rtl::OUString& path) + { return is_UNC_path(path.getStr()); } + + //##################################################### + void parse_UNC_path(const sal_Unicode* path, UNCComponents* puncc) + { + OSL_PRECOND(is_UNC_path(path), "Precondition violated: No UNC path"); + OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) != -1, "Path must not contain slashes"); + + const sal_Unicode* pend = path + rtl_ustr_getLength(path); + const sal_Unicode* ppos = path + 2; + + puncc->server_.begin_ = ppos; + while ((ppos < pend) && (*ppos != BACKSLASH)) + ppos++; + + puncc->server_.end_ = ppos; + + if (BACKSLASH == *ppos) + { + puncc->share_.begin_ = ++ppos; + while ((ppos < pend) && (*ppos != BACKSLASH)) + ppos++; + + puncc->share_.end_ = ppos; + + if (BACKSLASH == *ppos) + { + puncc->resource_.begin_ = ++ppos; + while (ppos < pend) + ppos++; + + puncc->resource_.end_ = ppos; + } + } + + OSL_POSTCOND(puncc->server_.isPresent() && puncc->share_.isPresent(), \ + "Postcondition violated: Invalid UNC path detected"); + } + + //##################################################### + void parse_UNC_path(const rtl::OUString& path, UNCComponents* puncc) + { parse_UNC_path(path.getStr(), puncc); } + + + //##################################################### + bool has_path_parent(const sal_Unicode* path) + { + // Has the given path a parent or are we already there, + // e.g. 'c:\' or '\\server\share\'? + + bool has_parent = false; + if (is_UNC_path(path)) + { + UNCComponents unc_comp; + parse_UNC_path(path, &unc_comp); + has_parent = unc_comp.resource_.isPresent(); + } + else + { + has_parent = !osl::systemPathIsLogicalDrivePattern(path); + } + return has_parent; + } + + //##################################################### + inline bool has_path_parent(const rtl::OUString& path) + { return has_path_parent(path.getStr()); } + +} // end namespace private + +//##################################################### +// volume handling functions +//##################################################### + +//##################################################### +oslFileError SAL_CALL osl_unmountVolumeDevice( oslVolumeDeviceHandle Handle ) +{ + if ( Handle ) + return osl_File_E_None; + else + return osl_File_E_INVAL; +} + +//##################################################### +oslFileError SAL_CALL osl_automountVolumeDevice( oslVolumeDeviceHandle Handle ) +{ + if ( Handle ) + return osl_File_E_None; + else + return osl_File_E_INVAL; +} + +//##################################################### +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; +} + +//##################################################### +oslFileError SAL_CALL osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle ) +{ + if ( Handle ) + { + rtl_uString_release( (rtl_uString *)Handle ); + return osl_File_E_None; + } + else + return osl_File_E_INVAL; +} + +//##################################################### +oslFileError SAL_CALL 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; +} + +//################################################################## +// directory handling functions +//################################################################## + +#define DIRECTORYITEM_DRIVE 0 +#define DIRECTORYITEM_FILE 1 +#define DIRECTORYITEM_SERVER 2 + +struct DirectoryItem_Impl +{ + UINT uType; + union { + WIN32_FIND_DATA FindData; + TCHAR cDriveString[MAX_PATH]; + }; + rtl_uString* m_pFullPath; + BOOL bFullPathNormalized; + int nRefCount; +}; + +//##################################################### + +#define DIRECTORYTYPE_LOCALROOT 0 +#define DIRECTORYTYPE_NETROOT 1 +#define DIRECTORYTYPE_NETRESORCE 2 +#define DIRECTORYTYPE_FILESYSTEM 3 + +struct Directory_Impl +{ + UINT uType; + union { + HANDLE hDirectory; + HANDLE hEnumDrives; + }; + rtl_uString* m_pDirectoryPath; +}; + +//##################################################### + +typedef struct tagDRIVEENUM +{ + LPCTSTR lpIdent; + TCHAR cBuffer[/*('Z' - 'A' + 1) * sizeof("A:\\") + 1*/256]; + LPCTSTR lpCurrent; +} DRIVEENUM, * PDRIVEENUM, FAR * LPDRIVEENUM; + +//##################################################### + +static HANDLE WINAPI OpenLogicalDrivesEnum(void) +{ + LPDRIVEENUM pEnum = (LPDRIVEENUM)HeapAlloc( GetProcessHeap(), 0, sizeof(DRIVEENUM) ); + if ( pEnum ) + { + DWORD dwNumCopied = GetLogicalDriveStrings( (sizeof(pEnum->cBuffer) - 1) / sizeof(TCHAR), pEnum->cBuffer ); + + if ( dwNumCopied && dwNumCopied < sizeof(pEnum->cBuffer) / sizeof(TCHAR) ) + { + pEnum->lpCurrent = pEnum->cBuffer; + pEnum->lpIdent = L"tagDRIVEENUM"; + } + else + { + HeapFree( GetProcessHeap(), 0, pEnum ); + pEnum = NULL; + } + } + return pEnum ? (HANDLE)pEnum : INVALID_HANDLE_VALUE; +} + +//##################################################### +static BOOL WINAPI EnumLogicalDrives(HANDLE hEnum, LPTSTR lpBuffer) +{ + BOOL fSuccess = FALSE; + LPDRIVEENUM pEnum = (LPDRIVEENUM)hEnum; + + if ( pEnum ) + { + int nLen = _tcslen( pEnum->lpCurrent ); + + if ( nLen ) + { + CopyMemory( lpBuffer, pEnum->lpCurrent, (nLen + 1) * sizeof(TCHAR) ); + pEnum->lpCurrent += nLen + 1; + fSuccess = TRUE; + } + else + SetLastError( ERROR_NO_MORE_FILES ); + } + else + SetLastError( ERROR_INVALID_HANDLE ); + + return fSuccess; +} + +//##################################################### +static BOOL WINAPI CloseLogicalDrivesEnum(HANDLE hEnum) +{ + BOOL fSuccess = FALSE; + LPDRIVEENUM pEnum = (LPDRIVEENUM)hEnum; + + if ( pEnum ) + { + HeapFree( GetProcessHeap(), 0, pEnum ); + fSuccess = TRUE; + } + else + SetLastError( ERROR_INVALID_HANDLE ); + + return fSuccess; +} + +//##################################################### +typedef struct tagDIRECTORY +{ + HANDLE hFind; + WIN32_FIND_DATA aFirstData; +} DIRECTORY, *PDIRECTORY, FAR *LPDIRECTORY; + +//##################################################### +static HANDLE WINAPI OpenDirectory( rtl_uString* pPath) +{ + LPDIRECTORY pDirectory = NULL; + + if ( pPath ) + { + sal_uInt32 nLen = rtl_uString_getLength( pPath ); + if ( nLen ) + { + TCHAR* pSuffix = 0; + sal_uInt32 nSuffLen = 0; + + if ( pPath->buffer[nLen - 1] != L'\\' ) + { + pSuffix = L"\\*.*"; + nSuffLen = 4; + } + else + { + pSuffix = L"*.*"; + nSuffLen = 3; + } + + TCHAR* szFileMask = reinterpret_cast< TCHAR* >( rtl_allocateMemory( sizeof( TCHAR ) * ( nLen + nSuffLen + 1 ) ) ); + + _tcscpy( szFileMask, reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pPath ) ) ); + _tcscat( szFileMask, pSuffix ); + + pDirectory = (LPDIRECTORY)HeapAlloc(GetProcessHeap(), 0, sizeof(DIRECTORY)); + pDirectory->hFind = FindFirstFile(szFileMask, &pDirectory->aFirstData); + + if (!IsValidHandle(pDirectory->hFind)) + { + if ( GetLastError() != ERROR_NO_MORE_FILES ) + { + HeapFree(GetProcessHeap(), 0, pDirectory); + pDirectory = NULL; + } + } + } + } + + return (HANDLE)pDirectory; +} + +//##################################################### +BOOL WINAPI EnumDirectory(HANDLE hDirectory, LPWIN32_FIND_DATA pFindData) +{ + BOOL fSuccess = FALSE; + LPDIRECTORY pDirectory = (LPDIRECTORY)hDirectory; + + if ( pDirectory ) + { + BOOL fValid; + + do + { + if ( pDirectory->aFirstData.cFileName[0] ) + { + *pFindData = pDirectory->aFirstData; + fSuccess = TRUE; + pDirectory->aFirstData.cFileName[0] = 0; + } + else if ( IsValidHandle( pDirectory->hFind ) ) + fSuccess = FindNextFile( pDirectory->hFind, pFindData ); + else + { + fSuccess = FALSE; + SetLastError( ERROR_NO_MORE_FILES ); + } + + fValid = fSuccess && _tcscmp( TEXT("."), pFindData->cFileName ) != 0 && _tcscmp( TEXT(".."), pFindData->cFileName ) != 0; + + } while( fSuccess && !fValid ); + } + else + SetLastError( ERROR_INVALID_HANDLE ); + + return fSuccess; +} + +//##################################################### +static BOOL WINAPI CloseDirectory(HANDLE hDirectory) +{ + BOOL fSuccess = FALSE; + LPDIRECTORY pDirectory = (LPDIRECTORY)hDirectory; + + if (pDirectory) + { + if (IsValidHandle(pDirectory->hFind)) + fSuccess = FindClose(pDirectory->hFind); + + fSuccess = HeapFree(GetProcessHeap(), 0, pDirectory) && fSuccess; + } + else + SetLastError(ERROR_INVALID_HANDLE); + + return fSuccess; +} + +//##################################################### +static oslFileError osl_openLocalRoot( + rtl_uString *strDirectoryPath, oslDirectory *pDirectory) +{ + rtl_uString *strSysPath = NULL; + oslFileError error; + + if ( !pDirectory ) + return osl_File_E_INVAL; + + *pDirectory = NULL; + + error = _osl_getSystemPathFromFileURL( strDirectoryPath, &strSysPath, sal_False ); + if ( osl_File_E_None == error ) + { + Directory_Impl *pDirImpl; + + pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory( sizeof(Directory_Impl))); + ZeroMemory( pDirImpl, sizeof(Directory_Impl) ); + rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strSysPath ); + + /* Append backslash if neccessary */ + + /* @@@ToDo + use function ensure backslash + */ + sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath ); + if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' ) + { + rtl_uString* pCurDir = 0; + rtl_uString* pBackSlash = 0; + + rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath ); + rtl_uString_newFromAscii( &pBackSlash, "\\" ); + rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash ); + rtl_uString_release( pBackSlash ); + rtl_uString_release( pCurDir ); + } + + pDirImpl->uType = DIRECTORYTYPE_LOCALROOT; + pDirImpl->hEnumDrives = OpenLogicalDrivesEnum(); + + /* @@@ToDo + Use IsValidHandle(...) + */ + if ( pDirImpl->hEnumDrives != INVALID_HANDLE_VALUE ) + { + *pDirectory = (oslDirectory)pDirImpl; + error = osl_File_E_None; + } + else + { + if ( pDirImpl ) + { + if ( pDirImpl->m_pDirectoryPath ) + { + rtl_uString_release( pDirImpl->m_pDirectoryPath ); + pDirImpl->m_pDirectoryPath = 0; + } + + rtl_freeMemory(pDirImpl); + pDirImpl = 0; + } + + error = oslTranslateFileError( GetLastError() ); + } + + rtl_uString_release( strSysPath ); + } + return error; +} + +//##################################################### +static oslFileError SAL_CALL osl_openFileDirectory( + rtl_uString *strDirectoryPath, oslDirectory *pDirectory) +{ + oslFileError error = osl_File_E_None; + + if ( !pDirectory ) + return osl_File_E_INVAL; + *pDirectory = NULL; + + Directory_Impl *pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory(sizeof(Directory_Impl))); + ZeroMemory( pDirImpl, sizeof(Directory_Impl) ); + rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strDirectoryPath ); + + /* Append backslash if neccessary */ + + /* @@@ToDo + use function ensure backslash + */ + sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath ); + if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' ) + { + rtl_uString* pCurDir = 0; + rtl_uString* pBackSlash = 0; + + rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath ); + rtl_uString_newFromAscii( &pBackSlash, "\\" ); + rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash ); + rtl_uString_release( pBackSlash ); + rtl_uString_release( pCurDir ); + } + + + pDirImpl->uType = DIRECTORYTYPE_FILESYSTEM; + pDirImpl->hDirectory = OpenDirectory( pDirImpl->m_pDirectoryPath ); + + if ( !pDirImpl->hDirectory ) + { + error = oslTranslateFileError( GetLastError() ); + + if ( pDirImpl->m_pDirectoryPath ) + { + rtl_uString_release( pDirImpl->m_pDirectoryPath ); + pDirImpl->m_pDirectoryPath = 0; + } + + rtl_freeMemory(pDirImpl), pDirImpl = 0; + } + + *pDirectory = (oslDirectory)(pDirImpl); + return error; +} + +//##################################################### +static oslFileError SAL_CALL osl_openNetworkServer( + rtl_uString *strSysDirPath, oslDirectory *pDirectory) +{ + NETRESOURCEW aNetResource; + HANDLE hEnum; + DWORD dwError; + + ZeroMemory( &aNetResource, sizeof(aNetResource) ); + + aNetResource.lpRemoteName = reinterpret_cast<LPWSTR>(strSysDirPath->buffer); + + dwError = WNetOpenEnumW( + RESOURCE_GLOBALNET, + RESOURCETYPE_DISK, + RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER, + &aNetResource, + &hEnum ); + + if ( ERROR_SUCCESS == dwError ) + { + Directory_Impl *pDirImpl; + + pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory(sizeof(Directory_Impl))); + ZeroMemory( pDirImpl, sizeof(Directory_Impl) ); + pDirImpl->uType = DIRECTORYTYPE_NETROOT; + pDirImpl->hDirectory = hEnum; + *pDirectory = (oslDirectory)pDirImpl; + } + return oslTranslateFileError( dwError ); +} + +//############################################# +static DWORD create_dir_with_callback( + rtl_uString * dir_path, + oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, + void* pData) +{ + // Create the specified directory and call the + // user specified callback function. On success + // the function returns ERROR_SUCCESS else a Win32 error code. + + BOOL bCreated = FALSE; + + bCreated = CreateDirectoryW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( dir_path )), NULL ); + + if ( bCreated ) + { + if (aDirectoryCreationCallbackFunc) + { + rtl::OUString url; + _osl_getFileURLFromSystemPath(dir_path, &(url.pData)); + aDirectoryCreationCallbackFunc(pData, url.pData); + } + return ERROR_SUCCESS; + } + return GetLastError(); +} + +//############################################# +static int path_make_parent(sal_Unicode* path) +{ + /* Cut off the last part of the given path to + get the parent only, e.g. 'c:\dir\subdir' -> + 'c:\dir' or '\\share\sub\dir' -> '\\share\sub' + @return The position where the path has been cut + off (this is the posistion of the last backslash). + If there are no more parents 0 will be returned, + e.g. 'c:\' or '\\Share' have no more parents */ + + OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) != -1, "Path must not contain slashes"); + OSL_PRECOND(has_path_parent(path), "Path must have a parent"); + + sal_Unicode* pos_last_backslash = path + rtl_ustr_lastIndexOfChar(path, BACKSLASH); + *pos_last_backslash = 0; + return (pos_last_backslash - path); +} + +//############################################# +static DWORD create_dir_recursively_( + rtl_uString * dir_path, + oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, + void* pData) +{ + OSL_PRECOND( + rtl_ustr_lastIndexOfChar_WithLength(dir_path->buffer, dir_path->length, BACKSLASH) != dir_path->length, + "Path must not end with a backslash"); + + DWORD w32_error = create_dir_with_callback( + dir_path, aDirectoryCreationCallbackFunc, pData); + if (w32_error == ERROR_SUCCESS) + return ERROR_SUCCESS; + + if ((w32_error != ERROR_PATH_NOT_FOUND) || !has_path_parent(dir_path->buffer)) + return w32_error; + + int pos = path_make_parent(dir_path->buffer); // dir_path->buffer[pos] = 0, restore below + + w32_error = create_dir_recursively_( + dir_path, aDirectoryCreationCallbackFunc, pData); + + dir_path->buffer[pos] = BACKSLASH; // restore + + if (ERROR_SUCCESS != w32_error) + return w32_error; + + 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(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 oslTranslateFileError(create_dir_recursively_( + sys_path.pData, aDirectoryCreationCallbackFunc, pData)); +} + +//##################################################### +oslFileError SAL_CALL osl_createDirectory(rtl_uString* strPath) +{ + rtl_uString *strSysPath = NULL; + oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + + if ( osl_File_E_None == error ) + { + BOOL bCreated = FALSE; + + bCreated = CreateDirectoryW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strSysPath )), NULL ); + + if ( !bCreated ) + { + /*@@@ToDo + The following case is a hack because the ucb or the webtop had some + problems with the error code that CreateDirectory returns in + case the path is only a logical drive, should be removed! + */ + + const sal_Unicode *pBuffer = rtl_uString_getStr( strSysPath ); + sal_Int32 nLen = rtl_uString_getLength( strSysPath ); + + if ( + ( ( pBuffer[0] >= 'A' && pBuffer[0] <= 'Z' ) || + ( pBuffer[0] >= 'a' && pBuffer[0] <= 'z' ) ) && + pBuffer[1] == ':' && ( nLen ==2 || ( nLen == 3 && pBuffer[2] == '\\' ) ) + ) + SetLastError( ERROR_ALREADY_EXISTS ); + + error = oslTranslateFileError( GetLastError() ); + } + + rtl_uString_release( strSysPath ); + } + return error; +} + +//##################################################### +oslFileError SAL_CALL osl_removeDirectory(rtl_uString* strPath) +{ + rtl_uString *strSysPath = NULL; + oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + + if ( osl_File_E_None == error ) + { + if ( RemoveDirectory( reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )) ) ) + error = osl_File_E_None; + else + error = oslTranslateFileError( GetLastError() ); + + rtl_uString_release( strSysPath ); + } + return error; +} + +//##################################################### +oslFileError SAL_CALL osl_openDirectory(rtl_uString *strDirectoryPath, oslDirectory *pDirectory) +{ + oslFileError error; + + if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath->buffer, "file:///" ) ) + error = osl_openLocalRoot( strDirectoryPath, pDirectory ); + else + { + rtl_uString *strSysDirectoryPath = NULL; + DWORD dwPathType; + + error = _osl_getSystemPathFromFileURL( strDirectoryPath, &strSysDirectoryPath, sal_False ); + + if ( osl_File_E_None != error ) + return error; + + dwPathType = IsValidFilePath( strSysDirectoryPath, NULL, VALIDATEPATH_NORMAL, NULL ); + + if ( dwPathType & PATHTYPE_IS_SERVER ) + { + error = osl_openNetworkServer( strSysDirectoryPath, pDirectory ); + } + else + error = osl_openFileDirectory( strSysDirectoryPath, pDirectory ); + + rtl_uString_release( strSysDirectoryPath ); + } + return error; +} + +//##################################################### +static oslFileError SAL_CALL osl_getNextNetResource( + oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint ) +{ + Directory_Impl *pDirImpl = (Directory_Impl *)Directory; + DirectoryItem_Impl *pItemImpl = NULL; + BYTE buffer[16384]; + LPNETRESOURCEW lpNetResource = (LPNETRESOURCEW)buffer; + DWORD dwError, dwCount, dwBufSize; + + uHint = uHint; /* to get no warning */ + + if ( !pItem ) + return osl_File_E_INVAL; + *pItem = NULL; + + if ( !pDirImpl ) + return osl_File_E_INVAL; + + dwCount = 1; + dwBufSize = sizeof(buffer); + dwError = WNetEnumResource( pDirImpl->hDirectory, &dwCount, lpNetResource, &dwBufSize ); + + switch ( dwError ) + { + case NO_ERROR: + case ERROR_MORE_DATA: + { + pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); + if ( !pItemImpl ) + return osl_File_E_NOMEM; + + ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); + pItemImpl->uType = DIRECTORYITEM_DRIVE; + osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); + + wcscpy( pItemImpl->cDriveString, lpNetResource->lpRemoteName ); + + *pItem = pItemImpl; + } + return osl_File_E_None; + case ERROR_NO_MORE_ITEMS: + return osl_File_E_NOENT; + default: + return oslTranslateFileError( dwError ); + } +} + +//##################################################### +static oslFileError SAL_CALL osl_getNextDrive( + oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint ) +{ + Directory_Impl *pDirImpl = (Directory_Impl *)Directory; + DirectoryItem_Impl *pItemImpl = NULL; + BOOL fSuccess; + + uHint = uHint; /* avoid warnings */ + + if ( !pItem ) + return osl_File_E_INVAL; + *pItem = NULL; + + if ( !pDirImpl ) + return osl_File_E_INVAL; + + pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); + if ( !pItemImpl ) + return osl_File_E_NOMEM; + + ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); + pItemImpl->uType = DIRECTORYITEM_DRIVE; + osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); + fSuccess = EnumLogicalDrives( pDirImpl->hEnumDrives, pItemImpl->cDriveString ); + + if ( fSuccess ) + { + *pItem = pItemImpl; + return osl_File_E_None; + } + else + { + if ( pItemImpl->m_pFullPath ) + { + rtl_uString_release( pItemImpl->m_pFullPath ); + pItemImpl->m_pFullPath = 0; + } + + rtl_freeMemory( pItemImpl ); + return oslTranslateFileError( GetLastError() ); + } +} + +//##################################################### +static oslFileError SAL_CALL osl_getNextFileItem( + oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint) +{ + Directory_Impl *pDirImpl = (Directory_Impl *)Directory; + DirectoryItem_Impl *pItemImpl = NULL; + BOOL fFound; + + uHint = uHint; /* avoid warnings */ + + if ( !pItem ) + return osl_File_E_INVAL; + *pItem = NULL; + + if ( !pDirImpl ) + return osl_File_E_INVAL; + + pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); + if ( !pItemImpl ) + return osl_File_E_NOMEM; + + memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) ); + fFound = EnumDirectory( pDirImpl->hDirectory, &pItemImpl->FindData ); + + if ( fFound ) + { + pItemImpl->uType = DIRECTORYITEM_FILE; + pItemImpl->nRefCount = 1; + + rtl_uString* pTmpFileName = 0; + rtl_uString_newFromStr( &pTmpFileName, reinterpret_cast<const sal_Unicode *>(pItemImpl->FindData.cFileName) ); + rtl_uString_newConcat( &pItemImpl->m_pFullPath, pDirImpl->m_pDirectoryPath, pTmpFileName ); + rtl_uString_release( pTmpFileName ); + + pItemImpl->bFullPathNormalized = FALSE; + *pItem = (oslDirectoryItem)pItemImpl; + return osl_File_E_None; + } + else + { + if ( pItemImpl->m_pFullPath ) + { + rtl_uString_release( pItemImpl->m_pFullPath ); + pItemImpl->m_pFullPath = 0; + } + + rtl_freeMemory( pItemImpl ); + return oslTranslateFileError( GetLastError() ); + } +} + +//##################################################### +oslFileError SAL_CALL osl_getNextDirectoryItem( + oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint) +{ + Directory_Impl *pDirImpl = (Directory_Impl *)Directory; + + /* Assume failure */ + + if ( !pItem ) + return osl_File_E_INVAL; + *pItem = NULL; + + if ( !pDirImpl ) + return osl_File_E_INVAL; + + switch ( pDirImpl->uType ) + { + case DIRECTORYTYPE_LOCALROOT: + return osl_getNextDrive( Directory, pItem, uHint ); + case DIRECTORYTYPE_NETROOT: + return osl_getNextNetResource( Directory, pItem, uHint ); + case DIRECTORYTYPE_FILESYSTEM: + return osl_getNextFileItem( Directory, pItem, uHint ); + default: + return osl_File_E_INVAL; + } +} + +//##################################################### +oslFileError SAL_CALL osl_closeDirectory(oslDirectory Directory) +{ + Directory_Impl *pDirImpl = (Directory_Impl *)Directory; + oslFileError eError = osl_File_E_INVAL; + + if ( pDirImpl ) + { + switch ( pDirImpl->uType ) + { + case DIRECTORYTYPE_FILESYSTEM: + eError = CloseDirectory( pDirImpl->hDirectory ) ? osl_File_E_None : oslTranslateFileError( GetLastError() ); + break; + case DIRECTORYTYPE_LOCALROOT: + eError = CloseLogicalDrivesEnum( pDirImpl->hEnumDrives ) ? osl_File_E_None : oslTranslateFileError( GetLastError() ); + break; + case DIRECTORYTYPE_NETROOT: + { + DWORD err = WNetCloseEnum(pDirImpl->hDirectory); + eError = (err == NO_ERROR) ? osl_File_E_None : oslTranslateFileError(err); + } + break; + default: + OSL_ENSURE( 0, "Invalid directory type" ); + break; + } + + if ( pDirImpl->m_pDirectoryPath ) + { + rtl_uString_release( pDirImpl->m_pDirectoryPath ); + pDirImpl->m_pDirectoryPath = 0; + } + + rtl_freeMemory(pDirImpl); + } + return eError; +} + +//##################################################### +/* Different types of paths */ +typedef enum _PATHTYPE +{ + PATHTYPE_SYNTAXERROR = 0, + PATHTYPE_NETROOT, + PATHTYPE_NETSERVER, + PATHTYPE_VOLUME, + PATHTYPE_FILE +} PATHTYPE; + +oslFileError SAL_CALL osl_getDirectoryItem(rtl_uString *strFilePath, oslDirectoryItem *pItem) +{ + oslFileError error = osl_File_E_None; + rtl_uString* strSysFilePath = NULL; + PATHTYPE type = PATHTYPE_FILE; + DWORD dwPathType; + + /* Assume failure */ + + if ( !pItem ) + return osl_File_E_INVAL; + + *pItem = NULL; + + + error = _osl_getSystemPathFromFileURL( strFilePath, &strSysFilePath, sal_False ); + + if ( osl_File_E_None != error ) + return error; + + dwPathType = IsValidFilePath( strSysFilePath, NULL, VALIDATEPATH_NORMAL, NULL ); + + 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 ) + { + ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); + pItemImpl->uType = DIRECTORYITEM_SERVER; + + osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); + rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath ); + + // Assign a title anyway + { + int iSrc = 2; + int iDst = 0; + + while( iSrc < strSysFilePath->length && strSysFilePath->buffer[iSrc] && strSysFilePath->buffer[iSrc] != '\\' ) + { + pItemImpl->FindData.cFileName[iDst++] = strSysFilePath->buffer[iSrc++]; + } + } + + *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 ) + { + ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); + pItemImpl->uType = DIRECTORYITEM_DRIVE; + + osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); + + _tcscpy( pItemImpl->cDriveString, reinterpret_cast<LPCTSTR>(strSysFilePath->buffer) ); + pItemImpl->cDriveString[0] = _toupper( pItemImpl->cDriveString[0] ); + + if ( pItemImpl->cDriveString[_tcslen(pItemImpl->cDriveString) - 1] != '\\' ) + _tcscat( pItemImpl->cDriveString, TEXT( "\\" ) ); + + *pItem = pItemImpl; + } + } + break; + case PATHTYPE_SYNTAXERROR: + case PATHTYPE_NETROOT: + case PATHTYPE_FILE: + { + HANDLE hFind; + WIN32_FIND_DATA aFindData; + + if ( strSysFilePath->length > 0 && strSysFilePath->buffer[strSysFilePath->length - 1] == '\\' ) + rtl_uString_newFromStr_WithLength( &strSysFilePath, strSysFilePath->buffer, strSysFilePath->length - 1 ); + + hFind = FindFirstFile( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(strSysFilePath)), &aFindData ); + + if ( hFind != INVALID_HANDLE_VALUE ) + { + DirectoryItem_Impl *pItemImpl = + reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); + + ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); + osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); + + CopyMemory( &pItemImpl->FindData, &aFindData, sizeof(WIN32_FIND_DATA) ); + rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath ); + + // MT: This costs 600ms startup time on fast v60x! + // GetCaseCorrectPathName( pItemImpl->szFullPath, pItemImpl->szFullPath, sizeof(pItemImpl->szFullPath) ); + + pItemImpl->uType = DIRECTORYITEM_FILE; + *pItem = pItemImpl; + FindClose( hFind ); + } + else + error = oslTranslateFileError( GetLastError() ); + } + break; + } + + if ( strSysFilePath ) + rtl_uString_release( strSysFilePath ); + + return error; +} + +//##################################################### +oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item ) +{ + DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; + + if ( !pItemImpl ) + return osl_File_E_INVAL; + + pItemImpl->nRefCount++; + return osl_File_E_None; +} + +//##################################################### +oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item ) +{ + DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; + + if ( !pItemImpl ) + return osl_File_E_INVAL; + + if ( ! --pItemImpl->nRefCount ) + { + if ( pItemImpl->m_pFullPath ) + { + rtl_uString_release( pItemImpl->m_pFullPath ); + pItemImpl->m_pFullPath = 0; + } + + rtl_freeMemory( pItemImpl ); + } + + return osl_File_E_None; +} + +//##################################################### +// volume / file info handling functions +//##################################################### + +//##################################################### +static inline bool is_floppy_A_present() +{ return (GetLogicalDrives() & 1); } + +//##################################################### +static inline bool is_floppy_B_present() +{ return (GetLogicalDrives() & 2); } + +//##################################################### +bool is_floppy_volume_mount_point(const rtl::OUString& path) +{ + // determines if a volume mount point shows to a floppy + // disk by comparing the unique volume names + static const LPCWSTR FLOPPY_A = L"A:\\"; + static const LPCWSTR FLOPPY_B = L"B:\\"; + + rtl::OUString p(path); + osl::systemPathEnsureSeparator(p); + + TCHAR vn[51]; + if (GetVolumeNameForVolumeMountPoint(reinterpret_cast<LPCTSTR>(p.getStr()), vn, ELEMENTS_OF_ARRAY(vn))) + { + TCHAR vnfloppy[51]; + if (is_floppy_A_present() && + GetVolumeNameForVolumeMountPoint(FLOPPY_A, vnfloppy, ELEMENTS_OF_ARRAY(vnfloppy)) && + (0 == wcscmp(vn, vnfloppy))) + return true; + + if (is_floppy_B_present() && + GetVolumeNameForVolumeMountPoint(FLOPPY_B, vnfloppy, ELEMENTS_OF_ARRAY(vnfloppy)) && + (0 == wcscmp(vn, vnfloppy))) + return true; + } + return false; +} + +//################################################ +static bool is_floppy_drive(const rtl::OUString& path) +{ + static const LPCWSTR FLOPPY_DRV_LETTERS = TEXT("AaBb"); + + // we must take into account that even a floppy + // drive may be mounted to a directory so checking + // for the drive letter alone is not sufficient + // we must compare the unique volume name with + // that of the available floppy disks + + const sal_Unicode* pszPath = path.getStr(); + return ((wcschr(FLOPPY_DRV_LETTERS, pszPath[0]) && (L':' == pszPath[1])) || is_floppy_volume_mount_point(path)); +} + +//##################################################### +static bool is_volume_mount_point(const rtl::OUString& path) +{ + rtl::OUString p(path); + osl::systemPathRemoveSeparator(p); + + bool is_volume_root = false; + + if (!is_floppy_drive(p)) + { + DWORD fattr = GetFileAttributes(reinterpret_cast<LPCTSTR>(p.getStr())); + + if ((INVALID_FILE_ATTRIBUTES != fattr) && + (FILE_ATTRIBUTE_REPARSE_POINT & fattr)) + { + WIN32_FIND_DATA find_data; + HANDLE h_find = FindFirstFile(reinterpret_cast<LPCTSTR>(p.getStr()), &find_data); + + if (IsValidHandle(h_find) && + (FILE_ATTRIBUTE_REPARSE_POINT & find_data.dwFileAttributes) && + (IO_REPARSE_TAG_MOUNT_POINT == find_data.dwReserved0)) + { + is_volume_root = true; + } + if (IsValidHandle(h_find)) + FindClose(h_find); + } + } + return is_volume_root; +} + +//############################################# +static UINT get_volume_mount_point_drive_type(const rtl::OUString& path) +{ + if (0 == path.getLength()) + return GetDriveType(NULL); + + rtl::OUString p(path); + osl::systemPathEnsureSeparator(p); + + TCHAR vn[51]; + if (GetVolumeNameForVolumeMountPoint(reinterpret_cast<LPCTSTR>(p.getStr()), vn, ELEMENTS_OF_ARRAY(vn))) + return GetDriveType(vn); + + return DRIVE_NO_ROOT_DIR; +} + +//############################################# +static inline bool is_drivetype_request(sal_uInt32 field_mask) +{ + return (field_mask & osl_VolumeInfo_Mask_Attributes); +} + +//############################################# +static oslFileError osl_get_drive_type( + const rtl::OUString& path, oslVolumeInfo* pInfo) +{ + // GetDriveType fails on empty volume mount points + // see Knowledge Base Q244089 + UINT drive_type; + if (is_volume_mount_point(path)) + drive_type = get_volume_mount_point_drive_type(path); + else + drive_type = GetDriveType(reinterpret_cast<LPCTSTR>(path.getStr())); + + if (DRIVE_NO_ROOT_DIR == drive_type) + return oslTranslateFileError(ERROR_INVALID_DRIVE); + + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + + switch (drive_type) + { + case DRIVE_CDROM: + pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable; + break; + case DRIVE_REMOVABLE: + pInfo->uAttributes |= osl_Volume_Attribute_Removeable; + if (is_floppy_drive(path)) + pInfo->uAttributes |= osl_Volume_Attribute_FloppyDisk; + break; + case DRIVE_FIXED: + pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk; + break; + case DRIVE_RAMDISK: + pInfo->uAttributes |= osl_Volume_Attribute_RAMDisk; + break; + case DRIVE_REMOTE: + pInfo->uAttributes |= osl_Volume_Attribute_Remote; + break; + case DRIVE_UNKNOWN: + pInfo->uAttributes = 0; + break; + default: + pInfo->uValidFields &= ~osl_VolumeInfo_Mask_Attributes; + pInfo->uAttributes = 0; + break; + } + return osl_File_E_None; +} + +//############################################# +static 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 rtl::OUString& path, oslVolumeInfo *pInfo) +{ + BOOL ret = GetDiskFreeSpaceEx( + reinterpret_cast<LPCTSTR>(path.getStr()), + (PULARGE_INTEGER)&(pInfo->uFreeSpace), + (PULARGE_INTEGER)&(pInfo->uTotalSpace), + NULL); + + if (ret) + { + pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace; + pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace | + osl_VolumeInfo_Mask_UsedSpace | + osl_VolumeInfo_Mask_FreeSpace; + } +} + +//############################################# +static 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)); +} + +//############################################# +static oslFileError get_filesystem_attributes( + const rtl::OUString& path, sal_uInt32 field_mask, oslVolumeInfo* pInfo) +{ + pInfo->uAttributes = 0; + + // osl_get_drive_type must be called first because + // this function resets osl_VolumeInfo_Mask_Attributes + // on failure + if (is_drivetype_request(field_mask)) + { + oslFileError osl_error = osl_get_drive_type(path, pInfo); + if (osl_File_E_None != osl_error) + return osl_error; + } + if (is_filesystem_attributes_request(field_mask)) + { + /* the following two parameters can not be longer than MAX_PATH+1 */ + WCHAR vn[MAX_PATH+1]; + WCHAR fsn[MAX_PATH+1]; + + DWORD serial; + DWORD mcl; + DWORD flags; + + LPCTSTR pszPath = reinterpret_cast<LPCTSTR>(path.getStr()); + if (GetVolumeInformation(pszPath, vn, MAX_PATH+1, &serial, &mcl, &flags, fsn, MAX_PATH+1)) + { + // Currently sal does not use this value, instead MAX_PATH is used + pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength; + pInfo->uMaxNameLength = mcl; + + // Should the uMaxPathLength be set to 32767, "\\?\" prefix allowes it + pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength; + pInfo->uMaxPathLength = MAX_PATH; + + pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName; + rtl_uString_newFromStr(&pInfo->ustrFileSystemName, reinterpret_cast<const sal_Unicode*>(fsn)); + + // volumes (even NTFS) will always be considered case + // insensitive because the Win32 API is not able to + // deal with case sensitive volumes see M$ Knowledge Base + // article 100625 that's why we never set the attribute + // osl_Volume_Attribute_Case_Sensitive + + if (flags & FS_CASE_IS_PRESERVED) + pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved; + + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + } + return osl_File_E_None; +} + +//##################################################### +static bool path_get_parent(rtl::OUString& path) +{ + OSL_PRECOND(path.lastIndexOf(SLASH) == -1, "Path must not have slashes"); + + if (!has_path_parent(path)) + { + sal_Int32 i = path.lastIndexOf(BACKSLASH); + if (-1 < i) + { + path = rtl::OUString(path.getStr(), i); + return true; + } + } + return false; +} + +//##################################################### +static void path_travel_to_volume_root(const rtl::OUString& system_path, rtl::OUString& volume_root) +{ + rtl::OUString sys_path(system_path); + + while(!is_volume_mount_point(sys_path) && path_get_parent(sys_path)) + /**/; + + volume_root = sys_path; + osl::systemPathEnsureSeparator(volume_root); +} + +//############################################# +oslFileError SAL_CALL osl_getVolumeInformation( + rtl_uString *ustrURL, oslVolumeInfo *pInfo, sal_uInt32 uFieldMask ) +{ + if (!pInfo) + return osl_File_E_INVAL; + + rtl::OUString system_path; + oslFileError error = _osl_getSystemPathFromFileURL(ustrURL, &system_path.pData, sal_False); + + if (osl_File_E_None != error) + return error; + + rtl::OUString volume_root; + path_travel_to_volume_root(system_path, volume_root); + + 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; + osl_getFileURLFromSystemPath(volume_root.pData, (rtl_uString**)&pInfo->pDeviceHandle); + } + + return osl_File_E_None; +} + +//##################################################### +static oslFileError SAL_CALL osl_getDriveInfo( + oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask) +{ + DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; + TCHAR cDrive[3] = TEXT("A:"); + TCHAR cRoot[4] = TEXT("A:\\"); + + if ( !pItemImpl ) + return osl_File_E_INVAL; + + pStatus->uValidFields = 0; + + cDrive[0] = pItemImpl->cDriveString[0]; + cRoot[0] = pItemImpl->cDriveString[0]; + + if ( uFieldMask & osl_FileStatus_Mask_FileName ) + { + if ( pItemImpl->cDriveString[0] == '\\' && pItemImpl->cDriveString[1] == '\\' ) + { + LPCWSTR lpFirstBkSlash = wcschr( &pItemImpl->cDriveString[2], '\\' ); + + if ( lpFirstBkSlash && lpFirstBkSlash[1] ) + { + LPCWSTR lpLastBkSlash = wcschr( &lpFirstBkSlash[1], '\\' ); + + if ( lpLastBkSlash ) + rtl_uString_newFromStr_WithLength( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(&lpFirstBkSlash[1]), lpLastBkSlash - lpFirstBkSlash - 1 ); + else + rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(&lpFirstBkSlash[1]) ); + pStatus->uValidFields |= osl_FileStatus_Mask_FileName; + } + } + else switch ( GetDriveType( cRoot ) ) + { + case DRIVE_REMOTE: + { + TCHAR szBuffer[1024]; + DWORD const dwBufsizeConst = ELEMENTS_OF_ARRAY(szBuffer); + DWORD dwBufsize = dwBufsizeConst; + + DWORD dwResult = WNetGetConnection( cDrive, szBuffer, &dwBufsize ); + if ( NO_ERROR == dwResult ) + { + TCHAR szFileName[dwBufsizeConst + 16]; + + swprintf( szFileName, L"%s [%s]", cDrive, szBuffer ); + rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(szFileName) ); + } + else + rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cDrive) ); + } + pStatus->uValidFields |= osl_FileStatus_Mask_FileName; + break; + case DRIVE_FIXED: + { + TCHAR szVolumeNameBuffer[1024]; + DWORD const dwBufsizeConst = ELEMENTS_OF_ARRAY(szVolumeNameBuffer); + + if ( GetVolumeInformation( cRoot, szVolumeNameBuffer, dwBufsizeConst, NULL, NULL, NULL, NULL, 0 ) ) + { + TCHAR szFileName[dwBufsizeConst + 16]; + + swprintf( szFileName, L"%s [%s]", cDrive, szVolumeNameBuffer ); + rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(szFileName) ); + } + else + rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cDrive) ); + } + pStatus->uValidFields |= osl_FileStatus_Mask_FileName; + break; + case DRIVE_CDROM: + case DRIVE_REMOVABLE: + pStatus->uValidFields |= osl_FileStatus_Mask_FileName; + rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cRoot) ); + break; + case DRIVE_UNKNOWN: + default: + break; + } + } + + 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, reinterpret_cast<const sal_Unicode*>(pItemImpl->cDriveString) ); + osl_getFileURLFromSystemPath( ustrSystemPath, &pStatus->ustrFileURL ); + rtl_uString_release( ustrSystemPath ); + pStatus->uValidFields |= osl_FileStatus_Mask_FileURL; + } + return osl_File_E_None; +} + +//##################################################### +static oslFileError SAL_CALL osl_getServerInfo( + oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask ) +{ + DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; + if ( !pItemImpl ) + return osl_File_E_INVAL; + + pStatus->uValidFields = 0; + + // pStatus->uValidFields |= osl_FileStatus_Mask_FileName; + + // if ( _tcscmp( pItemImpl->FindData.cFileName, TEXT(".") ) == 0 ) + // rtl_uString_newFromAscii( &pStatus->ustrFileName, "/" ); + // else + // rtl_uString_newFromStr( &pStatus->ustrFileName, pItemImpl->FindData.cFileName ); + + pStatus->eType = osl_File_Type_Directory; + pStatus->uValidFields |= osl_FileStatus_Mask_Type; + + if ( uFieldMask & osl_FileStatus_Mask_FileURL ) + { + osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL ); + 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; + + if ( !pItemImpl ) + return osl_File_E_INVAL; + + switch ( pItemImpl->uType ) + { + case DIRECTORYITEM_DRIVE: + return osl_getDriveInfo( Item, pStatus, uFieldMask ); + case DIRECTORYITEM_SERVER: + return osl_getServerInfo( Item, pStatus, uFieldMask ); + default: + break; + } + + if ( uFieldMask & osl_FileStatus_Mask_Validate ) + { + HANDLE hFind = FindFirstFile( reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pItemImpl->m_pFullPath ) ), &pItemImpl->FindData ); + + if ( hFind != INVALID_HANDLE_VALUE ) + FindClose( hFind ); + else + return oslTranslateFileError( GetLastError() ); + + 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) && + FileTimeToTimeValue( &pItemImpl->FindData.ftLastWriteTime, &pStatus->aModifyTime ) ) + pStatus->uValidFields |= osl_FileStatus_Mask_ModifyTime; + + if ( (uFieldMask & osl_FileStatus_Mask_AccessTime) && + FileTimeToTimeValue( &pItemImpl->FindData.ftLastAccessTime, &pStatus->aAccessTime ) ) + pStatus->uValidFields |= osl_FileStatus_Mask_AccessTime; + + if ( (uFieldMask & osl_FileStatus_Mask_CreationTime) && + FileTimeToTimeValue( &pItemImpl->FindData.ftCreationTime, &pStatus->aCreationTime ) ) + pStatus->uValidFields |= osl_FileStatus_Mask_CreationTime; + + /* Most of the fields are already set, regardless of requiered fields */ + + rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(pItemImpl->FindData.cFileName) ); + pStatus->uValidFields |= osl_FileStatus_Mask_FileName; + + if ((FILE_ATTRIBUTE_REPARSE_POINT & pItemImpl->FindData.dwFileAttributes) && + (IO_REPARSE_TAG_MOUNT_POINT == pItemImpl->FindData.dwReserved0)) + pStatus->eType = osl_File_Type_Volume; + else if (pItemImpl->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + pStatus->eType = osl_File_Type_Directory; + else + pStatus->eType = osl_File_Type_Regular; + + pStatus->uValidFields |= osl_FileStatus_Mask_Type; + + pStatus->uAttributes = pItemImpl->FindData.dwFileAttributes; + pStatus->uValidFields |= osl_FileStatus_Mask_Attributes; + + pStatus->uFileSize = (sal_uInt64)pItemImpl->FindData.nFileSizeLow + ((sal_uInt64)pItemImpl->FindData.nFileSizeHigh << 32); + pStatus->uValidFields |= osl_FileStatus_Mask_FileSize; + + if ( uFieldMask & osl_FileStatus_Mask_LinkTargetURL ) + { + osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrLinkTargetURL ); + + pStatus->uValidFields |= osl_FileStatus_Mask_LinkTargetURL; + } + + if ( uFieldMask & osl_FileStatus_Mask_FileURL ) + { + if ( !pItemImpl->bFullPathNormalized ) + { + sal_uInt32 nLen = rtl_uString_getLength( pItemImpl->m_pFullPath ); + ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); + sal_uInt32 nNewLen = GetCaseCorrectPathName( reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pItemImpl->m_pFullPath ) ), + ::osl::mingw_reinterpret_cast<LPTSTR>( aBuffer ), + aBuffer.getBufSizeInSymbols(), + sal_True ); + + if ( nNewLen ) + { + rtl_uString_newFromStr( &pItemImpl->m_pFullPath, aBuffer ); + pItemImpl->bFullPathNormalized = TRUE; + } + } + + osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL ); + pStatus->uValidFields |= osl_FileStatus_Mask_FileURL; + } + + return osl_File_E_None; +} + +//##################################################### +// file attributes handling functions +//##################################################### + +//############################################# +oslFileError SAL_CALL osl_setFileAttributes( + rtl_uString *ustrFileURL, + sal_uInt64 uAttributes ) +{ + oslFileError error; + rtl_uString *ustrSysPath = NULL; + DWORD dwFileAttributes; + BOOL fSuccess; + + // Converts the normalized path into a systempath + error = _osl_getSystemPathFromFileURL( ustrFileURL, &ustrSysPath, sal_False ); + + if ( osl_File_E_None != error ) + return error; + + dwFileAttributes = GetFileAttributes( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(ustrSysPath)) ); + + if ( (DWORD)-1 != dwFileAttributes ) + { + dwFileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN); + + if ( uAttributes & osl_File_Attribute_ReadOnly ) + dwFileAttributes |= FILE_ATTRIBUTE_READONLY; + + if ( uAttributes & osl_File_Attribute_Hidden ) + dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN; + + fSuccess = SetFileAttributes( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(ustrSysPath)), dwFileAttributes ); + } + else + fSuccess = FALSE; + + if ( !fSuccess ) + error = oslTranslateFileError( GetLastError() ); + + rtl_uString_release( ustrSysPath ); + + return error; +} + +//##################################################### +oslFileError SAL_CALL osl_setFileTime( + rtl_uString *filePath, + const TimeValue *aCreationTime, + const TimeValue *aLastAccessTime, + const TimeValue *aLastWriteTime) +{ + oslFileError error; + rtl_uString *sysPath=NULL; + FILETIME *lpCreationTime=NULL; + FILETIME *lpLastAccessTime=NULL; + FILETIME *lpLastWriteTime=NULL; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + HANDLE hFile; + BOOL fSuccess; + + + error=_osl_getSystemPathFromFileURL(filePath, &sysPath, sal_False); + + if (error==osl_File_E_INVAL) + return error; + + hFile=CreateFileW(reinterpret_cast<LPCWSTR>(rtl_uString_getStr(sysPath)), GENERIC_WRITE, 0, NULL , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + rtl_uString_release(sysPath); + + if (hFile==INVALID_HANDLE_VALUE) + return osl_File_E_NOENT; + + if (TimeValueToFileTime(aCreationTime, &ftCreationTime)) + lpCreationTime=&ftCreationTime; + + if (TimeValueToFileTime(aLastAccessTime, &ftLastAccessTime)) + lpLastAccessTime=&ftLastAccessTime; + + if (TimeValueToFileTime(aLastWriteTime, &ftLastWriteTime)) + lpLastWriteTime=&ftLastWriteTime; + + fSuccess=SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime); + + CloseHandle(hFile); + + if (!fSuccess) + return osl_File_E_INVAL; + else + return osl_File_E_None; +} diff --git a/sal/osl/w32/file_error.c b/sal/osl/w32/file_error.c new file mode 100644 index 000000000000..26e749cc5451 --- /dev/null +++ b/sal/osl/w32/file_error.c @@ -0,0 +1,151 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define UNICODE +#define _UNICODE +#define _WIN32_WINNT_0x0500 +#include "systools/win32/uwinapi.h" + +#include "file_error.h" + +#include "osl/diagnose.h" +#include "osl/thread.h" + +/* OS error to oslFileError values mapping table */ +struct osl_file_error_entry +{ + unsigned long oscode; /* OS return value */ + int errnocode; /* oslFileError code */ +}; + +static const struct osl_file_error_entry errtable[] = { + { ERROR_SUCCESS, 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 */ + { ERROR_UNEXP_NET_ERR, osl_File_E_NETWORK } /* 59 */ +}; + +/* The following two constants must be the minimum and maximum + values in the (contiguous) range of osl_File_E_xec Failure errors. +*/ +#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG +#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN + +/* These are the low and high value in the range of errors that are + access violations +*/ +#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT +#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED + +oslFileError oslTranslateFileError (/*DWORD*/ unsigned long dwError) +{ + static const int n = sizeof(errtable)/sizeof(errtable[0]); + + int i; + for (i = 0; i < n; ++i ) + { + if (dwError == errtable[i].oscode) + return (oslFileError)(errtable[i].errnocode); + } + + /* The error code wasn't in the table. We check for a range of + osl_File_E_ACCES errors or exec failure errors (ENOEXEC). + Otherwise osl_File_E_INVAL is returned. + */ + if ( (dwError >= MIN_EACCES_RANGE) && (dwError <= MAX_EACCES_RANGE) ) + return osl_File_E_ACCES; + else if ( (dwError >= MIN_EXEC_ERROR) && (dwError <= MAX_EXEC_ERROR) ) + return osl_File_E_NOEXEC; + else + return osl_File_E_INVAL; +} + +//##################################################### +#if OSL_DEBUG_LEVEL > 0 +void _osl_warnFile( const char *message, rtl_uString *ustrFile ) +{ + char szBuffer[2048]; + + if (ustrFile) + { + rtl_String *strFile = NULL; + + rtl_uString2String( &strFile, rtl_uString_getStr( ustrFile ), rtl_uString_getLength( ustrFile ), + osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + snprintf( szBuffer, sizeof(szBuffer), message, strFile->buffer ); + rtl_string_release( strFile ); + + message = szBuffer; + } + OSL_ENSURE( 0, message ); +} +#endif /* OSL_DEBUG_LEVEL */ diff --git a/sal/osl/w32/file_error.h b/sal/osl/w32/file_error.h new file mode 100644 index 000000000000..3815a021bb5e --- /dev/null +++ b/sal/osl/w32/file_error.h @@ -0,0 +1,51 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_OSL_FILE_ERROR_H +#define INCLUDED_OSL_FILE_ERROR_H + +#include "osl/file.h" +#include "rtl/ustring.h" + +#ifdef __cplusplus +extern "C" { +#endif + +oslFileError oslTranslateFileError (/*DWORD*/ unsigned long dwError); + +#if OSL_DEBUG_LEVEL > 0 +void _osl_warnFile (const char * message, rtl_uString * ustrFile); +#define OSL_ENSURE_FILE( cond, msg, file ) ( (cond) ? (void)0 : _osl_warnFile( msg, file ) ) +#else +#define OSL_ENSURE_FILE( cond, msg, file ) ((void)0) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_OSL_FILE_ERROR_H */ diff --git a/sal/osl/w32/file_url.cxx b/sal/osl/w32/file_url.cxx new file mode 100644 index 000000000000..90140cda97c6 --- /dev/null +++ b/sal/osl/w32/file_url.cxx @@ -0,0 +1,1143 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define UNICODE +#define _UNICODE +#define _WIN32_WINNT_0x0500 +#include "systools/win32/uwinapi.h" + +#include "file_url.h" +#include "file_error.h" + +#include "rtl/alloc.h" +#include "osl/diagnose.h" +#include "osl/file.h" +#include "osl/mutex.h" + +#include "path_helper.hxx" + +#include <stdio.h> +#include <tchar.h> + +#if OSL_DEBUG_LEVEL > 0 +#define OSL_ENSURE_FILE( cond, msg, file ) ( (cond) ? (void)0 : _osl_warnFile( msg, file ) ) +#else +#define OSL_ENSURE_FILE( cond, msg, file ) ((void)0) +#endif + +#define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0]))) + +#define WSTR_SYSTEM_ROOT_PATH L"\\\\.\\" +#define WSTR_LONG_PATH_PREFIX L"\\\\?\\" +#define WSTR_LONG_PATH_PREFIX_UNC L"\\\\?\\UNC\\" + + +//################################################################## +// FileURL functions +//################################################################## + +extern "C" oslMutex g_CurrentDirectoryMutex; /* Initialized in dllentry.c */ +oslMutex g_CurrentDirectoryMutex = 0; + +//##################################################### +static BOOL IsValidFilePathComponent( + LPCTSTR lpComponent, LPCTSTR *lppComponentEnd, DWORD dwFlags) +{ + LPCTSTR lpComponentEnd = NULL; + LPCTSTR lpCurrent = lpComponent; + BOOL fValid = TRUE; /* Assume success */ + TCHAR cLast = 0; + + /* Path component length must not exceed MAX_PATH even if long path with "\\?\" prefix is used */ + + while ( !lpComponentEnd && lpCurrent && lpCurrent - lpComponent < MAX_PATH ) + { + switch ( *lpCurrent ) + { + /* Both backslash and slash determine the end of a path component */ + case '\0': + case '/': + case '\\': + switch ( cLast ) + { + /* Component must not end with '.' or blank and can't be empty */ + + case '.': + if ( dwFlags & VALIDATEPATH_ALLOW_ELLIPSE ) + { + if ( 1 == lpCurrent - lpComponent ) + { + /* Current directory is O.K. */ + lpComponentEnd = lpCurrent; + break; + } + else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent ) + { + /* Parent directory is O.K. */ + lpComponentEnd = lpCurrent; + break; + } + } + case 0: + case ' ': + lpComponentEnd = lpCurrent - 1; + fValid = FALSE; + break; + default: + lpComponentEnd = lpCurrent; + break; + } + break; + /* '?' and '*' are valid wildcards but not valid file name characters */ + case '?': + case '*': + if ( dwFlags & VALIDATEPATH_ALLOW_WILDCARDS ) + break; + /* The following characters are reserved */ + case '<': + case '>': + case '\"': + case '|': + case ':': + lpComponentEnd = lpCurrent; + fValid = FALSE; + break; + default: + /* Characters below ASCII 32 are not allowed */ + if ( *lpCurrent < ' ' ) + { + lpComponentEnd = lpCurrent; + fValid = FALSE; + } + break; + } + cLast = *lpCurrent++; + } + + /* If we don't reached the end of the component the length of the component was to long + ( See condition of while loop ) */ + if ( !lpComponentEnd ) + { + fValid = FALSE; + lpComponentEnd = lpCurrent; + } + + /* Test wether the component specifies a device name what is not allowed */ + + // MT: PERFORMANCE: + // This is very expensive. A lot of calls to _tcsicmp. + // in SRC6870m71 67.000 calls of this method while empty office start result into more than 1.500.00 calls of _tcsicmp! + // Possible optimizations + // - Array should be const static + // - Sorted array, use binary search + // - More intelligent check for com1-9, lpt1-9 + // Maybe make szComponent upper case, don't search case intensitive + // Talked to HRO: Could be removed. Shouldn't be used in OOo, and if used for something like a filename, it will lead to an error anyway. + /* + if ( fValid ) + { + LPCTSTR alpDeviceNames[] = + { + TEXT("CON"), + TEXT("PRN"), + TEXT("AUX"), + TEXT("CLOCK$"), + TEXT("NUL"), + TEXT("LPT1"), + TEXT("LPT2"), + TEXT("LPT3"), + TEXT("LPT4"), + TEXT("LPT5"), + TEXT("LPT6"), + TEXT("LPT7"), + TEXT("LPT8"), + TEXT("LPT9"), + TEXT("COM1"), + TEXT("COM2"), + TEXT("COM3"), + TEXT("COM4"), + TEXT("COM5"), + TEXT("COM6"), + TEXT("COM7"), + TEXT("COM8"), + TEXT("COM9") + }; + + TCHAR szComponent[MAX_PATH]; + int nComponentLength; + LPCTSTR lpDot; + int i; + + // A device name with an extension is also invalid + lpDot = _tcschr( lpComponent, '.' ); + + if ( !lpDot || lpDot > lpComponentEnd ) + nComponentLength = lpComponentEnd - lpComponent; + else + nComponentLength = lpDot - lpComponent; + + _tcsncpy( szComponent, lpComponent, nComponentLength ); + szComponent[nComponentLength] = 0; + + for ( i = 0; i < sizeof( alpDeviceNames ) / sizeof(LPCTSTR); i++ ) + { + if ( 0 == _tcsicmp( szComponent, alpDeviceNames[i] ) ) + { + lpComponentEnd = lpComponent; + fValid = FALSE; + break; + } + } + } + */ + + if ( fValid ) + { + // Empty components are not allowed + if ( lpComponentEnd - lpComponent < 1 ) + fValid = FALSE; + + // If we reached the end of the string NULL is returned + else if ( !*lpComponentEnd ) + lpComponentEnd = NULL; + + } + + if ( lppComponentEnd ) + *lppComponentEnd = lpComponentEnd; + + return fValid; +} + +//##################################################### +#define CHARSET_SEPARATOR TEXT("\\/") + +DWORD IsValidFilePath(rtl_uString *path, LPCTSTR *lppError, DWORD dwFlags, rtl_uString **corrected) +{ + LPCTSTR lpszPath = reinterpret_cast< LPCTSTR >(path->buffer); + LPCTSTR lpComponent = lpszPath; + BOOL fValid = TRUE; + DWORD dwPathType = PATHTYPE_ERROR; + sal_Int32 nLength = rtl_uString_getLength( path ); + + if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE ) + dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE; + + if ( !lpszPath ) + fValid = FALSE; + + DWORD dwCandidatPathType = PATHTYPE_ERROR; + + if ( 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( path->buffer, nLength, reinterpret_cast<const sal_Unicode *>(WSTR_LONG_PATH_PREFIX_UNC), ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX_UNC) - 1, ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX_UNC) - 1 ) ) + { + /* This is long path in UNC notation */ + lpComponent = lpszPath + ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX_UNC) - 1; + dwCandidatPathType = PATHTYPE_ABSOLUTE_UNC | PATHTYPE_IS_LONGPATH; + } + else if ( 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( path->buffer, nLength, reinterpret_cast<const sal_Unicode *>(WSTR_LONG_PATH_PREFIX), ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1, ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1 ) ) + { + /* This is long path */ + lpComponent = lpszPath + ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1; + + if ( _istalpha( lpComponent[0] ) && ':' == lpComponent[1] ) + { + lpComponent += 2; + dwCandidatPathType = PATHTYPE_ABSOLUTE_LOCAL | PATHTYPE_IS_LONGPATH; + } + } + else if ( 2 == _tcsspn( lpszPath, CHARSET_SEPARATOR ) ) + { + /* The UNC path notation */ + lpComponent = lpszPath + 2; + dwCandidatPathType = PATHTYPE_ABSOLUTE_UNC; + } + else if ( _istalpha( lpszPath[0] ) && ':' == lpszPath[1] ) + { + /* Local path verification. Must start with <drive>: */ + lpComponent = lpszPath + 2; + dwCandidatPathType = PATHTYPE_ABSOLUTE_LOCAL; + } + + if ( ( dwCandidatPathType & PATHTYPE_MASK_TYPE ) == PATHTYPE_ABSOLUTE_UNC ) + { + fValid = IsValidFilePathComponent( lpComponent, &lpComponent, VALIDATEPATH_ALLOW_ELLIPSE ); + + /* So far we have a valid servername. Now let's see if we also have a network resource */ + + dwPathType = dwCandidatPathType; + + if ( fValid ) + { + if ( lpComponent && !*++lpComponent ) + lpComponent = NULL; + + if ( !lpComponent ) + { + #if 0 + /* We only have a Server specification what is invalid */ + + lpComponent = lpszPath; + fValid = FALSE; + #else + dwPathType |= PATHTYPE_IS_SERVER; + #endif + } + else + { + /* Now test the network resource */ + + fValid = IsValidFilePathComponent( lpComponent, &lpComponent, 0 ); + + /* If we now reached the end of the path, everything is O.K. */ + + + if ( fValid && (!lpComponent || lpComponent && !*++lpComponent ) ) + { + lpComponent = NULL; + dwPathType |= PATHTYPE_IS_VOLUME; + } + } + } + } + else if ( ( dwCandidatPathType & PATHTYPE_MASK_TYPE ) == PATHTYPE_ABSOLUTE_LOCAL ) + { + if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) ) + lpComponent++; + else if ( *lpComponent ) + fValid = FALSE; + + dwPathType = dwCandidatPathType; + + /* Now we are behind the backslash or it was a simple drive without backslash */ + + if ( fValid && !*lpComponent ) + { + lpComponent = NULL; + dwPathType |= PATHTYPE_IS_VOLUME; + } + } + else if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE ) + { + /* Can be a relative path */ + lpComponent = lpszPath; + + /* Relative path can start with a backslash */ + + if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) ) + { + lpComponent++; + if ( !*lpComponent ) + lpComponent = NULL; + } + + dwPathType = PATHTYPE_RELATIVE; + } + else + { + /* Anything else is an error */ + fValid = FALSE; + lpComponent = lpszPath; + } + + /* Now validate each component of the path */ + while ( fValid && lpComponent ) + { + // Correct path by merging consecutive slashes: + if (*lpComponent == '\\' && corrected != NULL) { + sal_Int32 i = lpComponent - lpszPath; + rtl_uString_newReplaceStrAt(corrected, path, i, 1, NULL); + //TODO: handle out-of-memory + lpszPath = reinterpret_cast< LPCTSTR >((*corrected)->buffer); + lpComponent = lpszPath + i; + } + + fValid = IsValidFilePathComponent( lpComponent, &lpComponent, dwFlags ); + + if ( fValid && lpComponent ) + { + lpComponent++; + + /* If the string behind the backslash is empty, we've done */ + + if ( !*lpComponent ) + lpComponent = NULL; + } + } + + /* The path can be longer than MAX_PATH only in case it has the longpath prefix */ + if ( fValid && !( dwPathType & PATHTYPE_IS_LONGPATH ) && _tcslen( lpszPath ) >= MAX_PATH ) + { + fValid = FALSE; + lpComponent = lpszPath + MAX_PATH; + } + + if ( lppError ) + *lppError = lpComponent; + + return fValid ? dwPathType : PATHTYPE_ERROR; +} + +//##################################################### +static sal_Int32 PathRemoveFileSpec(LPTSTR lpPath, LPTSTR lpFileName, sal_Int32 nFileBufLen ) +{ + sal_Int32 nRemoved = 0; + + if ( nFileBufLen ) + { + lpFileName[0] = 0; + LPTSTR lpLastBkSlash = _tcsrchr( lpPath, '\\' ); + LPTSTR lpLastSlash = _tcsrchr( lpPath, '/' ); + LPTSTR lpLastDelimiter = lpLastSlash > lpLastBkSlash ? lpLastSlash : lpLastBkSlash; + + if ( lpLastDelimiter ) + { + sal_Int32 nDelLen = _tcslen( lpLastDelimiter ); + if ( 1 == nDelLen ) + { + if ( lpLastDelimiter > lpPath && *(lpLastDelimiter - 1) != ':' ) + { + *lpLastDelimiter = 0; + *lpFileName = 0; + nRemoved = nDelLen; + } + } + else if ( nDelLen && nDelLen - 1 < nFileBufLen ) + { + _tcscpy( lpFileName, lpLastDelimiter + 1 ); + *(++lpLastDelimiter) = 0; + nRemoved = nDelLen - 1; + } + } + } + + return nRemoved; +} + +//##################################################### +// Undocumented in SHELL32.DLL ordinal 32 +static LPTSTR PathAddBackslash(LPTSTR lpPath, sal_Int32 nBufLen) +{ + LPTSTR lpEndPath = NULL; + + if ( lpPath ) + { + int nLen = _tcslen(lpPath); + + if ( !nLen || lpPath[nLen-1] != '\\' && lpPath[nLen-1] != '/' && nLen < nBufLen - 1 ) + { + lpEndPath = lpPath + nLen; + *lpEndPath++ = '\\'; + *lpEndPath = 0; + } + } + return lpEndPath; +} + +//##################################################### +// Same as GetLongPathName but also 95/NT4 +static DWORD GetCaseCorrectPathNameEx( + LPTSTR lpszPath, // path buffer to convert + DWORD cchBuffer, // size of path buffer + DWORD nSkipLevels, + BOOL bCheckExistence ) +{ + ::osl::LongPathBuffer< WCHAR > szFile( MAX_PATH + 1 ); + sal_Int32 nRemoved = PathRemoveFileSpec( lpszPath, szFile, MAX_PATH + 1 ); + sal_Int32 nLastStepRemoved = nRemoved; + while ( nLastStepRemoved && szFile[0] == 0 ) + { + // remove separators + nLastStepRemoved = PathRemoveFileSpec( lpszPath, szFile, MAX_PATH + 1 ); + nRemoved += nLastStepRemoved; + } + + if ( nRemoved ) + { + BOOL bSkipThis = FALSE; + + if ( 0 == _tcscmp( szFile, TEXT("..") ) ) + { + bSkipThis = TRUE; + nSkipLevels += 1; + } + else if ( 0 == _tcscmp( szFile, TEXT(".") ) ) + { + bSkipThis = TRUE; + } + else if ( nSkipLevels ) + { + bSkipThis = TRUE; + nSkipLevels--; + } + else + bSkipThis = FALSE; + + GetCaseCorrectPathNameEx( lpszPath, cchBuffer, nSkipLevels, bCheckExistence ); + + PathAddBackslash( lpszPath, cchBuffer ); + + /* Analyze parent if not only a trailing backslash was cutted but a real file spec */ + if ( !bSkipThis ) + { + if ( bCheckExistence ) + { + ::osl::LongPathBuffer< WCHAR > aShortPath( MAX_LONG_PATH ); + _tcscpy( aShortPath, lpszPath ); + _tcscat( aShortPath, szFile ); + + WIN32_FIND_DATA aFindFileData; + HANDLE hFind = FindFirstFile( aShortPath, &aFindFileData ); + + if ( IsValidHandle(hFind) ) + { + _tcscat( lpszPath, aFindFileData.cFileName[0] ? aFindFileData.cFileName : aFindFileData.cAlternateFileName ); + + FindClose( hFind ); + } + else + lpszPath[0] = 0; + } + else + { + /* add the segment name back */ + _tcscat( lpszPath, szFile ); + } + } + } + else + { + /* File specification can't be removed therefore the short path is either a drive + or a network share. If still levels to skip are left, the path specification + tries to travel below the file system root */ + if ( nSkipLevels ) + lpszPath[0] = 0; + else + _tcsupr( lpszPath ); + } + + return _tcslen( lpszPath ); +} + +//##################################################### +#define WSTR_SYSTEM_ROOT_PATH L"\\\\.\\" + +DWORD GetCaseCorrectPathName( + LPCTSTR lpszShortPath, // file name + LPTSTR lpszLongPath, // path buffer + DWORD cchBuffer, // size of path buffer + BOOL bCheckExistence +) +{ + /* Special handling for "\\.\" as system root */ + if ( lpszShortPath && 0 == wcscmp( lpszShortPath, WSTR_SYSTEM_ROOT_PATH ) ) + { + if ( cchBuffer >= ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) ) + { + wcscpy( lpszLongPath, WSTR_SYSTEM_ROOT_PATH ); + return ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1; + } + else + { + return ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1; + } + } + else if ( lpszShortPath ) + { + if ( _tcslen( lpszShortPath ) <= cchBuffer ) + { + _tcscpy( lpszLongPath, lpszShortPath ); + return GetCaseCorrectPathNameEx( lpszLongPath, cchBuffer, 0, bCheckExistence ); + } + } + + return 0; +} + + +//############################################# +static sal_Bool _osl_decodeURL( rtl_String* strUTF8, rtl_uString** pstrDecodedURL ) +{ + sal_Char *pBuffer; + const sal_Char *pSrcEnd; + const sal_Char *pSrc; + sal_Char *pDest; + sal_Int32 nSrcLen; + sal_Bool bValidEncoded = sal_True; /* Assume success */ + + /* The resulting decoded string length is shorter or equal to the source length */ + + nSrcLen = rtl_string_getLength(strUTF8); + pBuffer = reinterpret_cast<sal_Char*>(rtl_allocateMemory(nSrcLen + 1)); + + pDest = pBuffer; + pSrc = rtl_string_getStr(strUTF8); + pSrcEnd = pSrc + nSrcLen; + + /* Now decode the URL what should result in an UTF8 string */ + while ( bValidEncoded && pSrc < pSrcEnd ) + { + switch ( *pSrc ) + { + case '%': + { + sal_Char aToken[3]; + sal_Char aChar; + + pSrc++; + aToken[0] = *pSrc++; + aToken[1] = *pSrc++; + aToken[2] = 0; + + aChar = (sal_Char)strtoul( aToken, NULL, 16 ); + + /* The chars are path delimiters and must not be encoded */ + + if ( 0 == aChar || '\\' == aChar || '/' == aChar || ':' == aChar ) + bValidEncoded = sal_False; + else + *pDest++ = aChar; + } + break; + default: + *pDest++ = *pSrc++; + break; + } + } + + *pDest++ = 0; + + if ( bValidEncoded ) + { + rtl_string2UString( pstrDecodedURL, pBuffer, rtl_str_getLength(pBuffer), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pstrDecodedURL != 0); + } + + rtl_freeMemory( pBuffer ); + + return bValidEncoded; +} + +//############################################# +static void _osl_encodeURL( rtl_uString *strURL, rtl_String **pstrEncodedURL ) +{ + /* Encode non ascii characters within the URL */ + + rtl_String *strUTF8 = NULL; + sal_Char *pszEncodedURL; + const sal_Char *pURLScan; + sal_Char *pURLDest; + sal_Int32 nURLScanLen; + sal_Int32 nURLScanCount; + + rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); + + pszEncodedURL = (sal_Char*) rtl_allocateMemory( (rtl_string_getLength( strUTF8 ) * 3 + 1) * sizeof(sal_Char) ); + + pURLDest = pszEncodedURL; + pURLScan = rtl_string_getStr( strUTF8 ); + nURLScanLen = rtl_string_getLength( strUTF8 ); + nURLScanCount = 0; + + while ( nURLScanCount < nURLScanLen ) + { + sal_Char cCurrent = *pURLScan; + switch ( cCurrent ) + { + default: + if (!( ( cCurrent >= 'a' && cCurrent <= 'z' ) || ( cCurrent >= 'A' && cCurrent <= 'Z' ) || ( cCurrent >= '0' && cCurrent <= '9' ) ) ) + { + sprintf( pURLDest, "%%%02X", (unsigned char)cCurrent ); + pURLDest += 3; + break; + } + case '!': + case '\'': + case '(': + case ')': + case '*': + case '-': + case '.': + case '_': + case '~': + case '$': + case '&': + case '+': + case ',': + case '=': + case '@': + case ':': + case '/': + case '\\': + case '|': + *pURLDest++ = cCurrent; + break; + case 0: + break; + } + + pURLScan++; + nURLScanCount++; + } + + *pURLDest = 0; + + rtl_string_release( strUTF8 ); + rtl_string_newFromStr( pstrEncodedURL, pszEncodedURL ); + rtl_freeMemory( pszEncodedURL ); +} + +//############################################# + +oslFileError _osl_getSystemPathFromFileURL( rtl_uString *strURL, rtl_uString **pustrPath, sal_Bool bAllowRelative ) +{ + rtl_String *strUTF8 = NULL; + rtl_uString *strDecodedURL = NULL; + rtl_uString *strTempPath = NULL; + const sal_Unicode *pDecodedURL; + sal_uInt32 nDecodedLen; + sal_Bool bValidEncoded; + oslFileError nError = osl_File_E_INVAL; /* Assume failure */ + + /* If someone hasn't encoded the complete URL we convert it to UTF8 now to prevent from + having a mixed encoded URL later */ + + rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); + + /* If the length of strUTF8 and strURL differs it indicates that the URL was not correct encoded */ + + OSL_ENSURE_FILE( + strUTF8->length == strURL->length || + 0 != rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( strURL->buffer, strURL->length, "file:\\\\", 7 ) + ,"osl_getSystemPathFromFileURL: \"%s\" is not encoded !!!", strURL ); + + bValidEncoded = _osl_decodeURL( strUTF8, &strDecodedURL ); + + /* Release the encoded UTF8 string */ + rtl_string_release( strUTF8 ); + + if ( bValidEncoded ) + { + /* Replace backslashes and pipes */ + + rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '/', '\\' ); + rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '|', ':' ); + + pDecodedURL = rtl_uString_getStr( strDecodedURL ); + nDecodedLen = rtl_uString_getLength( strDecodedURL ); + + /* Must start with "file://" */ + if ( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\", 7 ) ) + { + sal_uInt32 nSkip; + + if ( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\\\", 8 ) ) + nSkip = 8; + else if ( + 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\localhost\\", 17 ) || + 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\127.0.0.1\\", 17 ) + ) + nSkip = 17; + else + nSkip = 5; + + /* Indicates local root */ + if ( nDecodedLen == nSkip ) + rtl_uString_newFromStr_WithLength( &strTempPath, reinterpret_cast<const sal_Unicode*>(WSTR_SYSTEM_ROOT_PATH), ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 ); + else + { + /* do not separate the directory and file case, so the maximal path lengs without prefix is MAX_PATH-12 */ + if ( nDecodedLen - nSkip <= MAX_PATH - 12 ) + { + rtl_uString_newFromStr_WithLength( &strTempPath, pDecodedURL + nSkip, nDecodedLen - nSkip ); + } + else + { + ::osl::LongPathBuffer< sal_Unicode > aBuf( MAX_LONG_PATH ); + sal_uInt32 nNewLen = GetCaseCorrectPathName( reinterpret_cast<LPCTSTR>(pDecodedURL + nSkip), + ::osl::mingw_reinterpret_cast<LPTSTR>(aBuf), + aBuf.getBufSizeInSymbols(), + sal_False ); + + if ( nNewLen <= MAX_PATH - 12 + || 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL + nSkip, nDecodedLen - nSkip, reinterpret_cast<const sal_Unicode*>(WSTR_SYSTEM_ROOT_PATH), ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1, ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 ) + || 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL + nSkip, nDecodedLen - nSkip, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX), ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1, ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1 ) ) + { + rtl_uString_newFromStr_WithLength( &strTempPath, aBuf, nNewLen ); + } + else if ( pDecodedURL[nSkip] == (sal_Unicode)'\\' && pDecodedURL[nSkip+1] == (sal_Unicode)'\\' ) + { + /* it should be an UNC path, use the according prefix */ + rtl_uString *strSuffix = NULL; + rtl_uString *strPrefix = NULL; + rtl_uString_newFromStr_WithLength( &strPrefix, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX_UNC), ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX_UNC ) - 1 ); + rtl_uString_newFromStr_WithLength( &strSuffix, aBuf + 2, nNewLen - 2 ); + + rtl_uString_newConcat( &strTempPath, strPrefix, strSuffix ); + + rtl_uString_release( strPrefix ); + rtl_uString_release( strSuffix ); + } + else + { + rtl_uString *strSuffix = NULL; + rtl_uString *strPrefix = NULL; + rtl_uString_newFromStr_WithLength( &strPrefix, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX), ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX ) - 1 ); + rtl_uString_newFromStr_WithLength( &strSuffix, aBuf, nNewLen ); + + rtl_uString_newConcat( &strTempPath, strPrefix, strSuffix ); + + rtl_uString_release( strPrefix ); + rtl_uString_release( strSuffix ); + } + } + } + + if ( IsValidFilePath( strTempPath, NULL, VALIDATEPATH_ALLOW_ELLIPSE, &strTempPath ) ) + nError = osl_File_E_None; + } + else if ( bAllowRelative ) /* This maybe a relative file URL */ + { + /* In future the relative path could be converted to absolute if it is too long */ + rtl_uString_assign( &strTempPath, strDecodedURL ); + + if ( IsValidFilePath( strTempPath, NULL, VALIDATEPATH_ALLOW_RELATIVE | VALIDATEPATH_ALLOW_ELLIPSE, &strTempPath ) ) + nError = osl_File_E_None; + } + /* + else + OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL ); + */ + + } + + if ( strDecodedURL ) + rtl_uString_release( strDecodedURL ); + + if ( osl_File_E_None == nError ) + rtl_uString_assign( pustrPath, strTempPath ); + + if ( strTempPath ) + rtl_uString_release( strTempPath ); + + /* + OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL ); + */ + + return nError; +} + +//############################################# +oslFileError _osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** pstrURL ) +{ + oslFileError nError = osl_File_E_INVAL; /* Assume failure */ + rtl_uString *strTempURL = NULL; + DWORD dwPathType = PATHTYPE_ERROR; + + if (strPath) + dwPathType = IsValidFilePath(strPath, NULL, VALIDATEPATH_ALLOW_RELATIVE, NULL); + + if (dwPathType) + { + rtl_uString *strTempPath = NULL; + + if ( dwPathType & PATHTYPE_IS_LONGPATH ) + { + rtl_uString *strBuffer = NULL; + sal_uInt32 nIgnore = 0; + sal_uInt32 nLength = 0; + + /* the path has the longpath prefix, lets remove it */ + switch ( dwPathType & PATHTYPE_MASK_TYPE ) + { + case PATHTYPE_ABSOLUTE_UNC: + nIgnore = ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX_UNC ) - 1; + OSL_ENSURE( nIgnore == 8, "Unexpected long path UNC prefix!" ); + + /* generate the normal UNC path */ + nLength = rtl_uString_getLength( strPath ); + rtl_uString_newFromStr_WithLength( &strBuffer, strPath->buffer + nIgnore - 2, nLength - nIgnore + 2 ); + strBuffer->buffer[0] = '\\'; + + rtl_uString_newReplace( &strTempPath, strBuffer, '\\', '/' ); + rtl_uString_release( strBuffer ); + break; + + case PATHTYPE_ABSOLUTE_LOCAL: + nIgnore = ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX ) - 1; + OSL_ENSURE( nIgnore == 4, "Unexpected long path prefix!" ); + + /* generate the normal path */ + nLength = rtl_uString_getLength( strPath ); + rtl_uString_newFromStr_WithLength( &strBuffer, strPath->buffer + nIgnore, nLength - nIgnore ); + + rtl_uString_newReplace( &strTempPath, strBuffer, '\\', '/' ); + rtl_uString_release( strBuffer ); + break; + + default: + OSL_ASSERT( "Unexpected long path format!" ); + rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' ); + break; + } + } + else + { + /* Replace backslashes */ + rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' ); + } + + switch ( dwPathType & PATHTYPE_MASK_TYPE ) + { + case PATHTYPE_RELATIVE: + rtl_uString_assign( &strTempURL, strTempPath ); + nError = osl_File_E_None; + break; + case PATHTYPE_ABSOLUTE_UNC: + rtl_uString_newFromAscii( &strTempURL, "file:" ); + rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath ); + nError = osl_File_E_None; + break; + case PATHTYPE_ABSOLUTE_LOCAL: + rtl_uString_newFromAscii( &strTempURL, "file:///" ); + rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath ); + nError = osl_File_E_None; + break; + default: + break; + } + + /* Release temp path */ + rtl_uString_release( strTempPath ); + } + + if ( osl_File_E_None == nError ) + { + rtl_String *strEncodedURL = NULL; + + /* Encode the URL */ + _osl_encodeURL( strTempURL, &strEncodedURL ); + + /* Provide URL via unicode string */ + rtl_string2UString( pstrURL, rtl_string_getStr(strEncodedURL), rtl_string_getLength(strEncodedURL), RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pstrURL != 0); + rtl_string_release( strEncodedURL ); + } + + /* Release temp URL */ + if ( strTempURL ) + rtl_uString_release( strTempURL ); + + /* + OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath ); + */ + return nError; +} + +//##################################################### +oslFileError SAL_CALL osl_getFileURLFromSystemPath( + rtl_uString* ustrPath, rtl_uString** pustrURL ) +{ + return _osl_getFileURLFromSystemPath( ustrPath, pustrURL ); +} + +//##################################################### +oslFileError SAL_CALL osl_getSystemPathFromFileURL( + rtl_uString *ustrURL, rtl_uString **pustrPath) +{ + return _osl_getSystemPathFromFileURL( ustrURL, pustrPath, sal_True ); +} + +//##################################################### +oslFileError SAL_CALL osl_searchFileURL( + rtl_uString *ustrFileName, + rtl_uString *ustrSystemSearchPath, + rtl_uString **pustrPath) +{ + rtl_uString *ustrUNCPath = NULL; + rtl_uString *ustrSysPath = NULL; + oslFileError error; + + /* First try to interpret the file name as an URL even a relative one */ + error = _osl_getSystemPathFromFileURL( ustrFileName, &ustrUNCPath, sal_True ); + + /* So far we either have an UNC path or something invalid + Now create a system path */ + if ( osl_File_E_None == error ) + error = _osl_getSystemPathFromFileURL( ustrUNCPath, &ustrSysPath, sal_True ); + + if ( osl_File_E_None == error ) + { + DWORD nBufferLength; + DWORD dwResult; + LPTSTR lpBuffer = NULL; + LPTSTR lpszFilePart; + + /* Repeat calling SearchPath ... + Start with MAX_PATH for the buffer. In most cases this + will be enough and does not force the loop to runtwice */ + dwResult = MAX_PATH; + + do + { + /* If search path is empty use a NULL pointer instead according to MSDN documentation of SearchPath */ + LPCTSTR lpszSearchPath = ustrSystemSearchPath && ustrSystemSearchPath->length ? reinterpret_cast<LPCTSTR>(ustrSystemSearchPath->buffer) : NULL; + LPCTSTR lpszSearchFile = reinterpret_cast<LPCTSTR>(ustrSysPath->buffer); + + /* Allocate space for buffer according to previous returned count of required chars */ + /* +1 is not neccessary if we follow MSDN documentation but for robustness we do so */ + nBufferLength = dwResult + 1; + lpBuffer = lpBuffer ? + reinterpret_cast<LPTSTR>(rtl_reallocateMemory(lpBuffer, nBufferLength * sizeof(TCHAR))) : + reinterpret_cast<LPTSTR>(rtl_allocateMemory(nBufferLength * sizeof(TCHAR))); + + dwResult = SearchPath( lpszSearchPath, lpszSearchFile, NULL, nBufferLength, lpBuffer, &lpszFilePart ); + } while ( dwResult && dwResult >= nBufferLength ); + + /* ... until an error occures or buffer is large enough. + dwResult == nBufferLength can not happen according to documentation but lets be robust ;-) */ + + if ( dwResult ) + { + rtl_uString_newFromStr( &ustrSysPath, reinterpret_cast<const sal_Unicode*>(lpBuffer) ); + error = osl_getFileURLFromSystemPath( ustrSysPath, pustrPath ); + } + else + { + WIN32_FIND_DATA aFindFileData; + HANDLE hFind; + + /* Somthing went wrong, perhaps the path was absolute */ + error = oslTranslateFileError( GetLastError() ); + + hFind = FindFirstFile( reinterpret_cast<LPCTSTR>(ustrSysPath->buffer), &aFindFileData ); + + if ( IsValidHandle(hFind) ) + { + error = osl_getFileURLFromSystemPath( ustrSysPath, pustrPath ); + FindClose( hFind ); + } + } + + rtl_freeMemory( lpBuffer ); + } + + if ( ustrSysPath ) + rtl_uString_release( ustrSysPath ); + + if ( ustrUNCPath ) + rtl_uString_release( ustrUNCPath ); + + return error; +} + +//##################################################### + +oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL ) +{ + oslFileError eError; + rtl_uString *ustrRelSysPath = NULL; + rtl_uString *ustrBaseSysPath = NULL; + + if ( ustrBaseURL && ustrBaseURL->length ) + { + eError = _osl_getSystemPathFromFileURL( ustrBaseURL, &ustrBaseSysPath, sal_False ); + OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" ); + + eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_True ); + } + else + { + eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_False ); + OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" ); + } + + if ( !eError ) + { + ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); + ::osl::LongPathBuffer< sal_Unicode > aCurrentDir( MAX_LONG_PATH ); + LPTSTR lpFilePart = NULL; + DWORD dwResult; + +/*@@@ToDo + Bad, bad hack, this only works if the base path + really exists which is not necessary according + to RFC2396 + The whole FileURL implementation should be merged + with the rtl/uri class. +*/ + if ( ustrBaseSysPath ) + { + osl_acquireMutex( g_CurrentDirectoryMutex ); + + GetCurrentDirectoryW( aCurrentDir.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aCurrentDir) ); + SetCurrentDirectoryW( reinterpret_cast<LPCWSTR>(ustrBaseSysPath->buffer) ); + } + + dwResult = GetFullPathNameW( reinterpret_cast<LPCWSTR>(ustrRelSysPath->buffer), aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), &lpFilePart ); + + if ( ustrBaseSysPath ) + { + SetCurrentDirectoryW( ::osl::mingw_reinterpret_cast<LPCWSTR>(aCurrentDir) ); + + osl_releaseMutex( g_CurrentDirectoryMutex ); + } + + if ( dwResult ) + { + if ( dwResult >= aBuffer.getBufSizeInSymbols() ) + eError = osl_File_E_INVAL; + else + { + rtl_uString *ustrAbsSysPath = NULL; + + rtl_uString_newFromStr( &ustrAbsSysPath, aBuffer ); + + eError = osl_getFileURLFromSystemPath( ustrAbsSysPath, pustrAbsoluteURL ); + + if ( ustrAbsSysPath ) + rtl_uString_release( ustrAbsSysPath ); + } + } + else + eError = oslTranslateFileError( GetLastError() ); + } + + if ( ustrBaseSysPath ) + rtl_uString_release( ustrBaseSysPath ); + + if ( ustrRelSysPath ) + rtl_uString_release( ustrRelSysPath ); + + return eError; +} + +//##################################################### +oslFileError SAL_CALL osl_getCanonicalName( rtl_uString *strRequested, rtl_uString **strValid ) +{ + rtl_uString_newFromString(strValid, strRequested); + return osl_File_E_None; +} diff --git a/sal/osl/w32/file_url.h b/sal/osl/w32/file_url.h new file mode 100644 index 000000000000..d9137c8c2fcc --- /dev/null +++ b/sal/osl/w32/file_url.h @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_OSL_FILE_URL_H +#define INCLUDED_OSL_FILE_URL_H + +#include "sal/types.h" +#include "rtl/ustring.h" +#include "osl/file.h" + +#ifdef _MSC_VER +#pragma warning(push,1) +#endif + +#define WINDOWS_LEAN_AND_MEAN +#include <windows.h> + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PATHTYPE_ERROR 0 +#define PATHTYPE_RELATIVE 1 +#define PATHTYPE_ABSOLUTE_UNC 2 +#define PATHTYPE_ABSOLUTE_LOCAL 3 +#define PATHTYPE_MASK_TYPE 0xFF +#define PATHTYPE_IS_VOLUME 0x0100 +#define PATHTYPE_IS_SERVER 0x0200 +#define PATHTYPE_IS_LONGPATH 0x0400 + +#define VALIDATEPATH_NORMAL 0x0000 +#define VALIDATEPATH_ALLOW_WILDCARDS 0x0001 +#define VALIDATEPATH_ALLOW_ELLIPSE 0x0002 +#define VALIDATEPATH_ALLOW_RELATIVE 0x0004 +#define VALIDATEPATH_ALLOW_UNC 0x0008 + +#define MAX_LONG_PATH 32767 + +DWORD IsValidFilePath ( + rtl_uString * path, + LPCTSTR * lppError, + DWORD dwFlags, + rtl_uString ** corrected +); + +DWORD GetCaseCorrectPathName ( + LPCTSTR lpszShortPath, // file name + LPTSTR lpszLongPath, // path buffer + DWORD cchBuffer, // size of path buffer + BOOL bCheckExistence +); + +oslFileError _osl_getSystemPathFromFileURL ( + rtl_uString * strURL, + rtl_uString ** pustrPath, + sal_Bool bAllowRelative +); + +oslFileError _osl_getFileURLFromSystemPath ( + rtl_uString * strPath, + rtl_uString ** pstrURL +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_OSL_FILE_URL_H */ diff --git a/sal/osl/w32/interlck.c b/sal/osl/w32/interlck.c new file mode 100644 index 000000000000..14589e56184a --- /dev/null +++ b/sal/osl/w32/interlck.c @@ -0,0 +1,142 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/interlck.h> +#include <osl/diagnose.h> + +extern int osl_isSingleCPU; + +/* For all Intel x86 above x486 we use a spezial inline assembler implementation. + The main reason is that WIN9? does not return the result of the operation. + Instead there is only returned a value greater than zero is the increment + result is greater than zero, but not the the result of the addition. + For Windows NT the native function could be used, because the correct result + is returned. Beacuse of simpler code maintance and performace reasons we use + on every x86-Windows-Platform the inline assembler implementation. +*/ + +/*****************************************************************************/ +/* osl_incrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount) +#ifdef _M_IX86 +#ifdef __MINGW32__ +{ + asm + ( + " movl %0, %%ecx\n" + " movl $1, %%eax\n" + " movl %1, %%edx\n" + " cmpl $0, %%edx\n" + " je 1f\n" + " xadd %%eax, (%%ecx)\n" + " jmp 2f\n" + "1:\n" + " lock xadd %%eax, (%%ecx)\n" + "2:\n" + " incl %%eax\n" + ::"m"(pCount),"m"(osl_isSingleCPU) + ); +} +#else +#pragma warning(disable: 4035) +{ + __asm + { + mov ecx, pCount + mov eax, 1 + mov edx, osl_isSingleCPU + cmp edx, 0 + je is_not_single + xadd dword ptr [ecx],eax + jmp cont + is_not_single: + lock xadd dword ptr [ecx],eax + cont: + inc eax + } +} +#pragma warning(default: 4035) +#endif +#else +#pragma message("WARNING: Using system InterlockedIncrement") +{ + return (InterlockedIncrement(pCount)); +} +#endif + +/*****************************************************************************/ +/* osl_decrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount) +#ifdef _M_IX86 +#ifdef __MINGW32__ +{ + asm + ( + " movl %0, %%ecx\n" + " orl $-1, %%eax\n" + " movl %1, %%edx\n" + " cmpl $0, %%edx\n" + " je 1f\n" + " xadd %%eax, (%%ecx)\n" + " jmp 2f\n" + "1:\n" + " lock xadd %%eax, (%%ecx)\n" + "2:\n" + " decl %%eax\n" + ::"m"(pCount),"m"(osl_isSingleCPU) + ); +} +#else +#pragma warning(disable: 4035) +{ + __asm + { + mov ecx, pCount + or eax, -1 + mov edx, osl_isSingleCPU + cmp edx, 0 + je is_not_single + xadd dword ptr [ecx],eax + jmp cont + is_not_single: + lock xadd dword ptr [ecx],eax + cont: + dec eax + } +} +#pragma warning(default: 4035) +#endif +#else +#pragma message("WARNING: Using system InterlockedDecrement") +{ + return (InterlockedDecrement(pCount)); +} +#endif diff --git a/sal/osl/w32/libutil.c b/sal/osl/w32/libutil.c new file mode 100644 index 000000000000..e00aef2e158d --- /dev/null +++ b/sal/osl/w32/libutil.c @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(push,1) /* disable warnings within system headers */ +#endif +#include <windows.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static BOOL g_bInit = FALSE; +static DWORD g_dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + +DWORD GetPlatformId() +{ + + if (!g_bInit) + { + OSVERSIONINFO aInfo; + + aInfo.dwOSVersionInfoSize = sizeof(aInfo); + if (GetVersionEx(&aInfo)) + g_dwPlatformId = aInfo.dwPlatformId; + + g_bInit = TRUE; + } + + return g_dwPlatformId; +} diff --git a/sal/osl/w32/module.cxx b/sal/osl/w32/module.cxx new file mode 100644 index 000000000000..b730bd3347df --- /dev/null +++ b/sal/osl/w32/module.cxx @@ -0,0 +1,480 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2010 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "system.h" +#include <tlhelp32.h> + +#include "file_url.h" +#include "path_helper.hxx" + +#include <osl/module.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/file.h> +#include <rtl/logfile.h> + +/* + under WIN32, we use the void* oslModule + as a WIN32 HANDLE (which is also a 32-bit value) +*/ + +/*****************************************************************************/ +/* osl_loadModule */ +/*****************************************************************************/ +oslModule SAL_CALL osl_loadModule(rtl_uString *strModuleName, sal_Int32 nRtldMode ) +{ + HINSTANCE hInstance; + UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + rtl_uString* Module = NULL; + oslModule ret = 0; + oslFileError nError; + + RTL_LOGFILE_TRACE1( "{ osl_loadModule start: %S", (LPTSTR)&strModuleName->buffer ); + + OSL_ASSERT(strModuleName); + + nRtldMode = nRtldMode; /* avoid warnings */ + + nError = osl_getSystemPathFromFileURL(strModuleName, &Module); + + if ( osl_File_E_None != nError ) + rtl_uString_assign(&Module, strModuleName); + + hInstance = LoadLibraryW(reinterpret_cast<LPCWSTR>(Module->buffer)); + if (hInstance == NULL) + hInstance = LoadLibraryExW(reinterpret_cast<LPCWSTR>(Module->buffer), NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); + + if (hInstance <= (HINSTANCE)HINSTANCE_ERROR) + hInstance = 0; + + ret = (oslModule) hInstance; + rtl_uString_release(Module); + SetErrorMode(errorMode); + + RTL_LOGFILE_TRACE1( "} osl_loadModule end: %S", (LPTSTR)&strModuleName->buffer ); + + return ret; +} + +/*****************************************************************************/ +/* osl_getModuleHandle */ +/*****************************************************************************/ + +sal_Bool SAL_CALL +osl_getModuleHandle(rtl_uString *pModuleName, oslModule *pResult) +{ + HINSTANCE hInstance = GetModuleHandleW(reinterpret_cast<LPCWSTR>(pModuleName->buffer)); + if( hInstance ) + { + *pResult = (oslModule) hInstance; + return sal_True; + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_unloadModule */ +/*****************************************************************************/ +void SAL_CALL osl_unloadModule(oslModule Module) +{ + FreeLibrary((HINSTANCE)Module); +} + +/*****************************************************************************/ +/* osl_getSymbol */ +/*****************************************************************************/ +void* SAL_CALL osl_getSymbol(oslModule Module, rtl_uString *strSymbolName) +{ + /* casting from a function pointer to a data pointer is invalid + be in this case unavoidable because the API has to stay + compitable we need to keep this function which returns a + void* by definition */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4054) +#endif + return (void*)(osl_getFunctionSymbol(Module, strSymbolName)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} + +/*****************************************************************************/ +/* osl_getFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL osl_getFunctionSymbol( oslModule Module, rtl_uString *strSymbolName ) +{ + rtl_String *symbolName = NULL; + oslGenericFunction address; + + OSL_ASSERT(Module); + OSL_ASSERT(strSymbolName); + + rtl_uString2String( + &symbolName, + strSymbolName->buffer, + strSymbolName->length, + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS + ); + + address=osl_getAsciiFunctionSymbol(Module, rtl_string_getStr(symbolName)); + rtl_string_release(symbolName); + + return address; +} + +/*****************************************************************************/ +/* osl_getAsciiFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL +osl_getAsciiFunctionSymbol( oslModule Module, const sal_Char *pSymbol ) +{ + oslGenericFunction fncAddr = NULL; + + if( pSymbol ) + fncAddr=(oslGenericFunction)GetProcAddress((HINSTANCE) Module, pSymbol); + + return fncAddr; +} + + + +/*****************************************************************************/ +/* osl_addressGetModuleURL */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Implementation for Windows 95, 98 and Me */ +/*****************************************************************************/ + +/* Undefine because there is no explicit "A" definition */ + +#ifdef MODULEENTRY32 +#undef MODULEENTRY32 +#endif + +#ifdef LPMODULEENTRY32 +#undef LPMODULEENTRY32 +#endif + +typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_PROC)( DWORD dwFlags, DWORD th32ProcessID ); +typedef BOOL (WINAPI *Module32First_PROC)( HANDLE hSnapshot, LPMODULEENTRY32 lpme32 ); +typedef BOOL (WINAPI *Module32Next_PROC)( HANDLE hSnapshot, LPMODULEENTRY32 lpme32 ); + +static sal_Bool SAL_CALL _osl_addressGetModuleURL_Windows( void *pv, rtl_uString **pustrURL ) +{ + sal_Bool bSuccess = sal_False; /* Assume failure */ + HMODULE hModKernel32 = GetModuleHandleA( "KERNEL32.DLL" ); + + if ( hModKernel32 ) + { + CreateToolhelp32Snapshot_PROC lpfnCreateToolhelp32Snapshot = (CreateToolhelp32Snapshot_PROC)GetProcAddress( hModKernel32, "CreateToolhelp32Snapshot" ); + Module32First_PROC lpfnModule32First = (Module32First_PROC)GetProcAddress( hModKernel32, "Module32First" ); + Module32Next_PROC lpfnModule32Next = (Module32Next_PROC)GetProcAddress( hModKernel32, "Module32Next" ); + + if ( lpfnCreateToolhelp32Snapshot && lpfnModule32First && lpfnModule32Next ) + { + HANDLE hModuleSnap = NULL; + DWORD dwProcessId = GetCurrentProcessId(); + + // Take a snapshot of all modules in the specified process. + + hModuleSnap = lpfnCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId ); + + if ( INVALID_HANDLE_VALUE != hModuleSnap ) + { + MODULEENTRY32 me32 = {0}; + + // Fill the size of the structure before using it. + + me32.dwSize = sizeof(MODULEENTRY32); + + // Walk the module list of the process, and find the module of + // interest. Then copy the information to the buffer pointed + // to by lpMe32 so that it can be returned to the caller. + + if ( lpfnModule32First(hModuleSnap, &me32) ) + { + do + { + if ( (BYTE *)pv >= (BYTE *)me32.hModule && (BYTE *)pv < (BYTE *)me32.hModule + me32.modBaseSize ) + { + rtl_uString *ustrSysPath = NULL; + + rtl_string2UString( &ustrSysPath, me32.szExePath, strlen(me32.szExePath), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(ustrSysPath != NULL); + osl_getFileURLFromSystemPath( ustrSysPath, pustrURL ); + rtl_uString_release( ustrSysPath ); + + bSuccess = sal_True; + } + + } while ( !bSuccess && lpfnModule32Next( hModuleSnap, &me32 ) ); + } + + + // Do not forget to clean up the snapshot object. + + CloseHandle (hModuleSnap); + } + + } + } + + return bSuccess; +} + +/***************************************************************************************/ +/* Implementation for Windows NT, 2K and XP (2K and XP could use the above method too) */ +/***************************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(push,1) /* disable warnings within system headers */ +#endif +#include <imagehlp.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +typedef BOOL (WINAPI *SymInitialize_PROC)( + HANDLE hProcess, + LPSTR UserSearchPath, + BOOL fInvadeProcess + ); + +typedef BOOL (WINAPI *SymCleanup_PROC)( + HANDLE hProcess + ); + +typedef BOOL (WINAPI *SymGetModuleInfo_PROC)( + HANDLE hProcess, + DWORD dwAddr, + PIMAGEHLP_MODULE ModuleInfo + ); + +/* Seems that IMAGEHLP.DLL is always availiable on NT 4. But MSDN from Platform SDK says Win 2K is required. MSDN from VS 6.0a says + it's O.K on NT 4 ???!!! + BTW: We are using ANSI function because not all version of IMAGEHLP.DLL contain Unicode support +*/ + +static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT4( void *pv, rtl_uString **pustrURL ) +{ + sal_Bool bSuccess = sal_False; /* Assume failure */ + + /* IMAGEHELP.DLL has a bug that it recursivly scans subdirectories of + the root when calling SymInitialize(), so we preferr DBGHELP.DLL + which exports the same symbols and is shipped with OOo */ + + HMODULE hModImageHelp = LoadLibrary( "DBGHELP.DLL" ); + + if ( !hModImageHelp ) + hModImageHelp = LoadLibrary( "IMAGEHLP.DLL" ); + + if ( hModImageHelp ) + { + SymGetModuleInfo_PROC lpfnSymGetModuleInfo; + SymInitialize_PROC lpfnSymInitialize; + SymCleanup_PROC lpfnSymCleanup; + + + lpfnSymInitialize = (SymInitialize_PROC)GetProcAddress( hModImageHelp, "SymInitialize" ); + lpfnSymCleanup = (SymCleanup_PROC)GetProcAddress( hModImageHelp, "SymCleanup" ); + lpfnSymGetModuleInfo = (SymGetModuleInfo_PROC)GetProcAddress( hModImageHelp, "SymGetModuleInfo" ); + + + if ( lpfnSymInitialize && lpfnSymCleanup && lpfnSymGetModuleInfo ) + { + IMAGEHLP_MODULE ModuleInfo; + ::osl::LongPathBuffer< sal_Char > aModuleFileName( MAX_LONG_PATH ); + LPSTR lpSearchPath = NULL; + + if ( GetModuleFileNameA( NULL, aModuleFileName, aModuleFileName.getBufSizeInSymbols() ) ) + { + char *pLastBkSlash = strrchr( aModuleFileName, '\\' ); + + if ( + pLastBkSlash && + pLastBkSlash > (sal_Char*)aModuleFileName + && *(pLastBkSlash - 1) != ':' + && *(pLastBkSlash - 1) != '\\' + ) + { + *pLastBkSlash = 0; + lpSearchPath = aModuleFileName; + } + } + + lpfnSymInitialize( GetCurrentProcess(), lpSearchPath, TRUE ); + + ZeroMemory( &ModuleInfo, sizeof(ModuleInfo) ); + ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); + + bSuccess = (sal_Bool)(!!lpfnSymGetModuleInfo( GetCurrentProcess(), (DWORD)pv, &ModuleInfo )); + + if ( bSuccess ) + { + /* #99182 On localized (non-english) NT4 and XP (!!!) for some libraries the LoadedImageName member of ModuleInfo isn't filled. Because + other members ModuleName and ImageName do not contain the full path we can cast the Member + BaseOfImage to a HMODULE (on NT it's the same) and use GetModuleFileName to retrieve the full + path of the loaded image */ + + if ( ModuleInfo.LoadedImageName[0] || GetModuleFileNameA( (HMODULE)ModuleInfo.BaseOfImage, ModuleInfo.LoadedImageName, sizeof(ModuleInfo.LoadedImageName) ) ) + { + rtl_uString *ustrSysPath = NULL; + + rtl_string2UString( &ustrSysPath, ModuleInfo.LoadedImageName, strlen(ModuleInfo.LoadedImageName), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(ustrSysPath != NULL); + osl_getFileURLFromSystemPath( ustrSysPath, pustrURL ); + rtl_uString_release( ustrSysPath ); + } + else + bSuccess = sal_False; + } + + lpfnSymCleanup( GetCurrentProcess() ); + } + + FreeLibrary( hModImageHelp ); + } + + return bSuccess; +} + + +typedef struct _MODULEINFO { + LPVOID lpBaseOfDll; + DWORD SizeOfImage; + LPVOID EntryPoint; +} MODULEINFO, *LPMODULEINFO; + +typedef BOOL (WINAPI *EnumProcessModules_PROC)( + HANDLE hProcess, // handle to the process + HMODULE * lphModule, // array to receive the module handles + DWORD cb, // size of the array + LPDWORD lpcbNeeded // receives the number of bytes returned +); + +typedef BOOL (WINAPI *GetModuleInformation_PROC)( + HANDLE hProcess, // handle to the process + HMODULE hModule, // handle to the module + LPMODULEINFO lpmodinfo, // structure that receives information + DWORD cb // size of the structure +); + +#define bufsizeof(buffer) (sizeof(buffer) / sizeof((buffer)[0])) + +/* This version can fail because PSAPI.DLL is not always part of NT 4 despite MSDN Libary 6.0a say so */ + +static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT( void *pv, rtl_uString **pustrURL ) +{ + sal_Bool bSuccess = sal_False; /* Assume failure */ + static HMODULE hModPsapi = NULL; + + if ( !hModPsapi ) + hModPsapi = LoadLibrary( "PSAPI.DLL" ); + + if ( hModPsapi ) + { + EnumProcessModules_PROC lpfnEnumProcessModules = (EnumProcessModules_PROC)GetProcAddress( hModPsapi, "EnumProcessModules" ); + GetModuleInformation_PROC lpfnGetModuleInformation = (GetModuleInformation_PROC)GetProcAddress( hModPsapi, "GetModuleInformation" ); + + if ( lpfnEnumProcessModules && lpfnGetModuleInformation ) + { + DWORD cbNeeded = 0; + HMODULE *lpModules = NULL; + DWORD nModules = 0; + UINT iModule = 0; + MODULEINFO modinfo; + + lpfnEnumProcessModules( GetCurrentProcess(), NULL, 0, &cbNeeded ); + + lpModules = (HMODULE *)_alloca( cbNeeded ); + lpfnEnumProcessModules( GetCurrentProcess(), lpModules, cbNeeded, &cbNeeded ); + + nModules = cbNeeded / sizeof(HMODULE); + + for ( iModule = 0; !bSuccess && iModule < nModules; iModule++ ) + { + lpfnGetModuleInformation( GetCurrentProcess(), lpModules[iModule], &modinfo, sizeof(modinfo) ); + + if ( (BYTE *)pv >= (BYTE *)modinfo.lpBaseOfDll && (BYTE *)pv < (BYTE *)modinfo.lpBaseOfDll + modinfo.SizeOfImage ) + { + ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); + rtl_uString *ustrSysPath = NULL; + + GetModuleFileNameW( lpModules[iModule], ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), aBuffer.getBufSizeInSymbols() ); + + rtl_uString_newFromStr( &ustrSysPath, aBuffer ); + osl_getFileURLFromSystemPath( ustrSysPath, pustrURL ); + rtl_uString_release( ustrSysPath ); + + bSuccess = sal_True; + } + } + } + + } + + return bSuccess; +} + +/*****************************************************************************/ +/* Dispatcher for osl_osl_addressGetModuleURL */ +/*****************************************************************************/ + +sal_Bool SAL_CALL osl_getModuleURLFromAddress( void *pv, rtl_uString **pustrURL ) +{ + /* Use ..._NT first because ..._NT4 is much slower */ + if ( IS_NT ) + return _osl_addressGetModuleURL_NT( pv, pustrURL ) || _osl_addressGetModuleURL_NT4( pv, pustrURL ); + else + return _osl_addressGetModuleURL_Windows( pv, pustrURL ); +} + +/*****************************************************************************/ +/* osl_getModuleURLFromFunctionAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress( oslGenericFunction addr, rtl_uString ** ppLibraryUrl ) +{ + /* casting a function pointer to a data pointer (void*) is + not allowed according to the C/C++ standards. In this case + it is unavoidable because we have to stay compatible we + cannot remove any function. */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4054) +#endif + return osl_getModuleURLFromAddress((void*)addr, ppLibraryUrl); +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} + + diff --git a/sal/osl/w32/mutex.c b/sal/osl/w32/mutex.c new file mode 100644 index 000000000000..db16459d7fe7 --- /dev/null +++ b/sal/osl/w32/mutex.c @@ -0,0 +1,206 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/mutex.h> +#include <osl/diagnose.h> + +/* + Implementation notes: + The void* hidden by oslMutex points to a WIN32 + CRITICAL_SECTION structure. +*/ + +typedef struct _oslMutexImpl { + CRITICAL_SECTION m_Mutex; + int m_Locks; + DWORD m_Owner; + DWORD m_Requests; +} oslMutexImpl; + +static BOOL (WINAPI *lpfTryEnterCriticalSection)(LPCRITICAL_SECTION) + = (BOOL (WINAPI *)(LPCRITICAL_SECTION))0xFFFFFFFF; + +static CRITICAL_SECTION MutexLock; + +/*****************************************************************************/ +/* osl_createMutex */ +/*****************************************************************************/ +oslMutex SAL_CALL osl_createMutex(void) +{ + oslMutexImpl *pMutexImpl; + + /* Window 95 does not support "TryEnterCriticalSection" */ + + if (lpfTryEnterCriticalSection == + (BOOL (WINAPI *)(LPCRITICAL_SECTION))0xFFFFFFFF) + { + OSVERSIONINFO VersionInformation = + + { + sizeof(OSVERSIONINFO), + 0, + 0, + 0, + 0, + "", + }; + + /* ts: Window 98 does not support "TryEnterCriticalSection" but export the symbol !!! + calls to that symbol always returns FALSE */ + if ( + GetVersionEx(&VersionInformation) && + (VersionInformation.dwPlatformId == VER_PLATFORM_WIN32_NT) + ) + { + lpfTryEnterCriticalSection = (BOOL (WINAPI *)(LPCRITICAL_SECTION)) + GetProcAddress(GetModuleHandle("KERNEL32"), + "TryEnterCriticalSection"); + } + else + { + lpfTryEnterCriticalSection = (BOOL (WINAPI *)(LPCRITICAL_SECTION))NULL; + } + + + InitializeCriticalSection(&MutexLock); + } + + pMutexImpl= calloc(sizeof(oslMutexImpl), 1); + + OSL_ASSERT(pMutexImpl); /* alloc successful? */ + + InitializeCriticalSection(&pMutexImpl->m_Mutex); + + return (oslMutex)pMutexImpl; +} + +/*****************************************************************************/ +/* osl_destroyMutex */ +/*****************************************************************************/ +void SAL_CALL osl_destroyMutex(oslMutex Mutex) +{ + oslMutexImpl *pMutexImpl = (oslMutexImpl *)Mutex; + + if (pMutexImpl) + { + DeleteCriticalSection(&pMutexImpl->m_Mutex); + free(pMutexImpl); + } +} + +/*****************************************************************************/ +/* osl_acquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireMutex(oslMutex Mutex) +{ + oslMutexImpl *pMutexImpl = (oslMutexImpl *)Mutex; + + OSL_ASSERT(Mutex); + + if (lpfTryEnterCriticalSection == NULL) + { + EnterCriticalSection(&MutexLock); + pMutexImpl->m_Requests++; + LeaveCriticalSection(&MutexLock); + + EnterCriticalSection(&pMutexImpl->m_Mutex); + + EnterCriticalSection(&MutexLock); + pMutexImpl->m_Requests--; + if (pMutexImpl->m_Locks++ == 0) + pMutexImpl->m_Owner = GetCurrentThreadId(); + LeaveCriticalSection(&MutexLock); + } + else + EnterCriticalSection(&pMutexImpl->m_Mutex); + + return sal_True; +} + +/*****************************************************************************/ +/* osl_tryToAcquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireMutex(oslMutex Mutex) +{ + sal_Bool ret = sal_False; + oslMutexImpl *pMutexImpl = (oslMutexImpl *)Mutex; + + OSL_ASSERT(Mutex); + + if (lpfTryEnterCriticalSection != NULL) + return (sal_Bool)(lpfTryEnterCriticalSection(&pMutexImpl->m_Mutex) != FALSE); + else + { + EnterCriticalSection(&MutexLock); + + if ( ((pMutexImpl->m_Requests == 0) && (pMutexImpl->m_Locks == 0)) || + (pMutexImpl->m_Owner == GetCurrentThreadId()) ) + ret = osl_acquireMutex(Mutex); + + LeaveCriticalSection(&MutexLock); + } + + return ret; +} + +/*****************************************************************************/ +/* osl_releaseMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseMutex(oslMutex Mutex) +{ + oslMutexImpl *pMutexImpl = (oslMutexImpl *)Mutex; + + OSL_ASSERT(Mutex); + + if (lpfTryEnterCriticalSection == NULL) + { + EnterCriticalSection(&MutexLock); + + if (--(pMutexImpl->m_Locks) == 0) + pMutexImpl->m_Owner = 0; + + LeaveCriticalSection(&MutexLock); + } + + LeaveCriticalSection(&pMutexImpl->m_Mutex); + + return sal_True; +} + +/*****************************************************************************/ +/* osl_getGlobalMutex */ +/*****************************************************************************/ + +/* initialized in dllentry.c */ +oslMutex g_Mutex; + +oslMutex * SAL_CALL osl_getGlobalMutex(void) +{ + return &g_Mutex; +} diff --git a/sal/osl/w32/nlsupport.c b/sal/osl/w32/nlsupport.c new file mode 100644 index 000000000000..ad9de5f8492c --- /dev/null +++ b/sal/osl/w32/nlsupport.c @@ -0,0 +1,231 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define UNICODE +#ifdef _MSC_VER +#pragma warning(push,1) /* disable warnings within system headers */ +#endif +#include <windows.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#include <wchar.h> + +#include <osl/mutex.h> +#include <osl/nlsupport.h> +#include <osl/diagnose.h> +#include <osl/process.h> +#include <rtl/tencinfo.h> + +struct EnumLocalesParams +{ + WCHAR Language[3]; + WCHAR Country[3]; + LCID Locale; +}; + +static DWORD g_dwTLSLocaleEncId = (DWORD) -1; + +/*****************************************************************************/ +/* callback function test +/* +/* osl_getTextEncodingFromLocale calls EnumSystemLocalesA, so that we don't +/* need to provide a unicode wrapper for this function under Win9x +/* that means the callback function has an ansi prototype and receives +/* the locale strings as ansi strings +/*****************************************************************************/ + +BOOL CALLBACK EnumLocalesProcA( LPSTR lpLocaleStringA ) +{ + struct EnumLocalesParams * params; + + LCID localeId; + LPSTR pszEndA; + + WCHAR langCode[4]; + + /* convert hex-string to LCID */ + localeId = strtol( lpLocaleStringA, &pszEndA, 16 ); + + /* check params received via TLS */ + params = (struct EnumLocalesParams *) TlsGetValue( g_dwTLSLocaleEncId ); + if( NULL == params || '\0' == params->Language[0] ) + return FALSE; + + /* + get the ISO language code for this locale + + remeber: we call the GetLocaleInfoW function + because the ansi version of this function returns + an error under WinNT/2000 when called with an + unicode only lcid + */ + if( GetLocaleInfo( localeId, LOCALE_SISO639LANGNAME , langCode, 4 ) ) + { + WCHAR ctryCode[4]; + + /* continue if language code does not match */ + if( 0 != wcscmp( langCode, params->Language ) ) + return TRUE; + + /* check if country code is set and equals the current locale */ + if( '\0' != params->Country[0] && GetLocaleInfo( localeId, LOCALE_SISO3166CTRYNAME , ctryCode, 4 ) ) + { + /* save return value in TLS and break if found desired locale */ + if( 0 == wcscmp( ctryCode, params->Country ) ) + { + params->Locale = localeId; + return FALSE; + } + } + else + { + /* fill with default values for that language */ + LANGID langId = LANGIDFROMLCID( localeId ); + + /* exchange sublanguage with SUBLANG_NEUTRAL */ + langId = MAKELANGID( PRIMARYLANGID( langId ), SUBLANG_NEUTRAL ); + + /* and use default sorting order */ + params->Locale = MAKELCID( langId, SORT_DEFAULT ); + + return FALSE; + } + } + + /* retry by going on */ + return TRUE; +} + + +/*****************************************************************************/ +/* GetTextEncodingFromLCID +/*****************************************************************************/ + +rtl_TextEncoding GetTextEncodingFromLCID( LCID localeId ) +{ + rtl_TextEncoding Encoding = RTL_TEXTENCODING_DONTKNOW; + WCHAR ansiCP[6]; + + /* query ansi codepage for given locale */ + if( localeId && GetLocaleInfo( localeId, LOCALE_IDEFAULTANSICODEPAGE, ansiCP, 6 ) ) + { + /* if GetLocaleInfo returns "0", it is a UNICODE only locale */ + if( 0 != wcscmp( ansiCP, L"0" ) ) + { + WCHAR *pwcEnd; + UINT codepage; + + /* values returned from GetLocaleInfo are dezimal based */ + codepage = wcstol( ansiCP, &pwcEnd, 10 ); + + /* find matching rtl encoding */ + Encoding = rtl_getTextEncodingFromWindowsCodePage( codepage ); + } + else + Encoding = RTL_TEXTENCODING_UNICODE; + } + + return Encoding; +} + + +/*****************************************************************************/ +/* osl_getTextEncodingFromLocale +/*****************************************************************************/ + +rtl_TextEncoding SAL_CALL osl_getTextEncodingFromLocale( rtl_Locale * pLocale ) +{ + struct EnumLocalesParams params = { L"", L"", 0 }; + + /* initialise global TLS id */ + if( (DWORD) -1 == g_dwTLSLocaleEncId ) + { + oslMutex globalMutex = * osl_getGlobalMutex(); + + /* initializing must be thread save */ + osl_acquireMutex( globalMutex ); + + if( (DWORD) -1 == g_dwTLSLocaleEncId ) + g_dwTLSLocaleEncId = TlsAlloc(); + + osl_releaseMutex( globalMutex ); + } + + /* if pLocale is NULL, use process locale as default */ + if( NULL == pLocale ) + osl_getProcessLocale( &pLocale ); + + /* copy in parameters to structure */ + if( pLocale && pLocale->Language ) + { + wcscpy( params.Language, pLocale->Language->buffer ); + + if( pLocale->Country ) + wcscpy( params.Country, pLocale->Country->buffer ); + + /* save pointer to local structure in TLS */ + TlsSetValue( g_dwTLSLocaleEncId, ¶ms ); + + /* enum all locales known to Windows */ + EnumSystemLocalesA( EnumLocalesProcA, LCID_SUPPORTED ); + + /* use the LCID found in iteration */ + return GetTextEncodingFromLCID( params.Locale ); + } + + return RTL_TEXTENCODING_DONTKNOW; +} + +/*****************************************************************************/ +/* imp_getProcessLocale +/*****************************************************************************/ + +void _imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + WCHAR langCode[4]; + WCHAR ctryCode[4]; + LCID localeId; + + OSL_ASSERT( ppLocale ); + + /* get the LCID to retrieve information from */ + localeId = GetUserDefaultLCID(); + + /* call GetLocaleInfo to retrieve the iso codes */ + if( GetLocaleInfo( localeId, LOCALE_SISO639LANGNAME , langCode, 4 ) && + GetLocaleInfo( localeId, LOCALE_SISO3166CTRYNAME , ctryCode, 4 ) ) + { + *ppLocale = rtl_locale_register( langCode, ctryCode, L"" ); + } + else + { + *ppLocale = rtl_locale_register( L"C", L"", L"" ); + } +} + + diff --git a/sal/osl/w32/path_helper.cxx b/sal/osl/w32/path_helper.cxx new file mode 100644 index 000000000000..a43ff8bca1d8 --- /dev/null +++ b/sal/osl/w32/path_helper.cxx @@ -0,0 +1,118 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +/******************************************************************* + Includes + ******************************************************************/ + +#include "path_helper.hxx" +#include <osl/diagnose.h> +#include <rtl/ustring.hxx> + +#include <algorithm> +#include <wchar.h> + +/******************************************************************* + Constants + ******************************************************************/ + +const rtl::OUString BACKSLASH = rtl::OUString::createFromAscii("\\"); +const rtl::OUString SLASH = rtl::OUString::createFromAscii("/"); + +/******************************************************************* + osl_systemPathEnsureSeparator + ******************************************************************/ + +void osl_systemPathEnsureSeparator(/*inout*/ rtl_uString** ppustrPath) +{ + OSL_PRECOND(ppustrPath && (NULL != *ppustrPath), \ + "osl_systemPathEnsureSeparator: Invalid parameter"); + + rtl::OUString path(*ppustrPath); + sal_Int32 i = std::max<sal_Int32>(path.lastIndexOf(BACKSLASH), path.lastIndexOf(SLASH)); + + if (i < (path.getLength()-1)) + { + path += BACKSLASH; + rtl_uString_assign(ppustrPath, path.pData); + } + + OSL_POSTCOND(path.lastIndexOf(BACKSLASH) == (path.getLength() - 1), \ + "osl_systemPathEnsureSeparator: Post condition failed"); +} + +/******************************************************************* + osl_systemPathRemoveSeparator + ******************************************************************/ + +void SAL_CALL osl_systemPathRemoveSeparator(/*inout*/ rtl_uString** ppustrPath) +{ + rtl::OUString path(*ppustrPath); + + if (!osl::systemPathIsLogicalDrivePattern(path)) + { + sal_Int32 i = std::max<sal_Int32>(path.lastIndexOf(BACKSLASH), path.lastIndexOf(SLASH)); + + if (i > -1 && (i == (path.getLength() - 1))) + { + path = rtl::OUString(path.getStr(), path.getLength() - 1); + rtl_uString_assign(ppustrPath, path.pData); + } + } +} + +/******************************************************************* + osl_is_logical_drive_pattern + ******************************************************************/ + +// is [A-Za-z]:[/|\]\0 +const sal_Char* LDP = ":"; +const sal_Char* LDP_WITH_BACKSLASH = ":\\"; +const sal_Char* LDP_WITH_SLASH = ":/"; + +// degenerated case returned by the Windows FileOpen dialog +// when someone enters for instance "x:filename", the Win32 +// API accepts this case +const sal_Char* LDP_WITH_DOT_BACKSLASH = ":.\\"; + +sal_Int32 osl_systemPathIsLogicalDrivePattern(/*in*/ const rtl_uString* pustrPath) +{ + const sal_Unicode* p = rtl_uString_getStr(const_cast<rtl_uString*>(pustrPath)); + if (iswalpha(*p++)) + { + return ((0 == rtl_ustr_ascii_compare(p, LDP)) || + (0 == rtl_ustr_ascii_compare(p, LDP_WITH_BACKSLASH)) || + (0 == rtl_ustr_ascii_compare(p, LDP_WITH_SLASH)) || + (0 == rtl_ustr_ascii_compare(p, LDP_WITH_DOT_BACKSLASH))); + } + return 0; +} + + diff --git a/sal/osl/w32/path_helper.h b/sal/osl/w32/path_helper.h new file mode 100644 index 000000000000..79341f538667 --- /dev/null +++ b/sal/osl/w32/path_helper.h @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _PATH_HELPER_H_ +#define _PATH_HELPER_H_ + +#include <sal/types.h> +#include <rtl/ustring.h> +#include <osl/file.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************* + osl_systemPathEnsureSeparator + Adds a trailing path separator to the given system path if not + already there and if the path is not the root path or a logical + drive alone + ******************************************************************/ + +void osl_systemPathEnsureSeparator(/*inout*/ rtl_uString** ppustrPath); + +/******************************************************************* + osl_systemPathRemoveSeparator + Removes the last separator from the given system path if any and + if the path is not the root path '\' + ******************************************************************/ + +void SAL_CALL osl_systemPathRemoveSeparator(/*inout*/ rtl_uString** ppustrPath); + +/******************************************************************* + osl_is_logical_drive_pattern + Returns whether a given path is only a logical drive pattern or not. + A logical drive pattern is something like "a:\", "c:\". + No logical drive pattern is something like "c:\test" + ******************************************************************/ + +sal_Int32 osl_systemPathIsLogicalDrivePattern(/*in*/ const rtl_uString* pustrPath); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sal/osl/w32/path_helper.hxx b/sal/osl/w32/path_helper.hxx new file mode 100644 index 000000000000..d157b42aa428 --- /dev/null +++ b/sal/osl/w32/path_helper.hxx @@ -0,0 +1,118 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifdef _MSC_VER +#pragma warning (disable : 4800) +#endif + +#ifndef _PATH_HELPER_HXX_ +#define _PATH_HELPER_HXX_ + +#include "path_helper.h" +#include <rtl/ustring.hxx> +#include <rtl/allocator.hxx> + +namespace osl +{ + +/******************************************************************* + osl_systemPathEnsureSeparator + Adds a trailing path separator to the given system path if not + already there and if the path is not the root path or a logical + drive alone + ******************************************************************/ + +inline void systemPathEnsureSeparator(/*inout*/ rtl::OUString& Path) +{ + osl_systemPathEnsureSeparator(&Path.pData); +} + +/******************************************************************* + osl_systemPathRemoveSeparator + Removes the last separator from the given system path if any and + if the path is not the root path '\' + ******************************************************************/ + +inline void systemPathRemoveSeparator(/*inout*/ rtl::OUString& Path) +{ + osl_systemPathRemoveSeparator(&Path.pData); +} + +/******************************************************************* + osl_systemPathIsLogicalDrivePattern + ******************************************************************/ + +inline bool systemPathIsLogicalDrivePattern(/*in*/ const rtl::OUString& path) +{ + return osl_systemPathIsLogicalDrivePattern(path.pData); +} + +/******************************************************************* + LongPathBuffer + ******************************************************************/ +template< class T > +class LongPathBuffer +{ + T* m_pBuffer; + sal_uInt32 m_nCharNum; + + LongPathBuffer(); + LongPathBuffer( const LongPathBuffer& ); + LongPathBuffer& operator=( const LongPathBuffer& ); + +public: + LongPathBuffer( sal_uInt32 nCharNum ) + : m_pBuffer( reinterpret_cast<T*>( rtl_allocateMemory( nCharNum * sizeof( T ) ) ) ) + , m_nCharNum( nCharNum ) + { + OSL_ENSURE( m_pBuffer, "Can not allocate the buffer!" ); + } + + ~LongPathBuffer() + { + if ( m_pBuffer ) + rtl_freeMemory( m_pBuffer ); + m_pBuffer = 0; + } + + sal_uInt32 getBufSizeInSymbols() + { + return m_nCharNum; + } + + operator T* () + { + return m_pBuffer; + } + +}; + + template< class U, class T > U mingw_reinterpret_cast(LongPathBuffer<T>& a) { return reinterpret_cast<U>(static_cast<T*>(a)); } + +} // end namespace osl + +#endif diff --git a/sal/osl/w32/pipe.c b/sal/osl/w32/pipe.c new file mode 100644 index 000000000000..bd5185a2ba2b --- /dev/null +++ b/sal/osl/w32/pipe.c @@ -0,0 +1,636 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include "pipeimpl.h" + +#include <osl/pipe.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/mutex.h> +#include <osl/semaphor.h> +#include <osl/conditn.h> +#include <osl/interlck.h> +#include <osl/process.h> + +#include <rtl/alloc.h> +#include <rtl/memory.h> + +#define PIPESYSTEM "\\\\.\\pipe\\" +#define PIPEPREFIX "OSL_PIPE_" + +typedef struct +{ + sal_uInt32 m_Size; + sal_uInt32 m_ReadPos; + sal_uInt32 m_WritePos; + BYTE m_Data[1]; + +} oslPipeBuffer; + +/*****************************************************************************/ +/* oslPipeImpl */ +/*****************************************************************************/ + +struct oslPipeImpl { + oslInterlockedCount m_Reference; + HANDLE m_File; + HANDLE m_NamedObject; + PSECURITY_ATTRIBUTES m_Security; + HANDLE m_ReadEvent; + HANDLE m_WriteEvent; + HANDLE m_AcceptEvent; + rtl_uString* m_Name; + oslPipeError m_Error; + sal_Bool m_bClosed; +}; + + +/*****************************************************************************/ +/* osl_create/destroy-PipeImpl */ +/*****************************************************************************/ + +static oslInterlockedCount nPipes = 0; + +oslPipe __osl_createPipeImpl(void) +{ + oslPipe pPipe; + + pPipe = (oslPipe) rtl_allocateZeroMemory(sizeof(struct oslPipeImpl)); + + pPipe->m_bClosed = sal_False; + pPipe->m_Reference = 0; + pPipe->m_Name = NULL; + pPipe->m_File = INVALID_HANDLE_VALUE; + pPipe->m_NamedObject = INVALID_HANDLE_VALUE; + + pPipe->m_ReadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + pPipe->m_WriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + pPipe->m_AcceptEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + return pPipe; +} + +void __osl_destroyPipeImpl(oslPipe pPipe) +{ + if (pPipe != NULL) + { + if ( pPipe->m_NamedObject != INVALID_HANDLE_VALUE && pPipe->m_NamedObject != NULL ) + CloseHandle( pPipe->m_NamedObject ); + + if (pPipe->m_Security != NULL) + { + rtl_freeMemory(pPipe->m_Security->lpSecurityDescriptor); + rtl_freeMemory(pPipe->m_Security); + } + + CloseHandle(pPipe->m_ReadEvent); + CloseHandle(pPipe->m_WriteEvent); + CloseHandle(pPipe->m_AcceptEvent); + + if (pPipe->m_Name) + rtl_uString_release(pPipe->m_Name); + + rtl_freeMemory(pPipe); + } +} + + + +/*****************************************************************************/ +/* osl_createPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_createPipe(rtl_uString *strPipeName, oslPipeOptions Options, + oslSecurity Security) +{ + rtl_uString* name = NULL; + rtl_uString* path = NULL; + rtl_uString* temp = NULL; + oslPipe pPipe; + + PSECURITY_ATTRIBUTES pSecAttr = NULL; + + rtl_uString_newFromAscii(&path, PIPESYSTEM); + rtl_uString_newFromAscii(&name, PIPEPREFIX); + + if ( /*IS_NT &&*/ Security) + { + rtl_uString *Ident = NULL; + rtl_uString *Delim = NULL; + + OSL_VERIFY(osl_getUserIdent(Security, &Ident)); + rtl_uString_newFromAscii(&Delim, "_"); + + rtl_uString_newConcat(&temp, name, Ident); + rtl_uString_newConcat(&name, temp, Delim); + + rtl_uString_release(Ident); + rtl_uString_release(Delim); + } + else + { + if (Options & osl_Pipe_CREATE) + { + PSECURITY_DESCRIPTOR pSecDesc; + + pSecDesc = (PSECURITY_DESCRIPTOR) rtl_allocateMemory(SECURITY_DESCRIPTOR_MIN_LENGTH); + + /* add a NULL disc. ACL to the security descriptor */ + OSL_VERIFY(InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)); + OSL_VERIFY(SetSecurityDescriptorDacl(pSecDesc, TRUE, (PACL) NULL, FALSE)); + + pSecAttr = rtl_allocateMemory(sizeof(SECURITY_ATTRIBUTES)); + pSecAttr->nLength = sizeof(SECURITY_ATTRIBUTES); + pSecAttr->lpSecurityDescriptor = pSecDesc; + pSecAttr->bInheritHandle = TRUE; + } + } + + rtl_uString_assign(&temp, name); + rtl_uString_newConcat(&name, temp, strPipeName); + + /* alloc memory */ + pPipe= __osl_createPipeImpl(); + osl_incrementInterlockedCount(&(pPipe->m_Reference)); + + /* build system pipe name */ + rtl_uString_assign(&temp, path); + rtl_uString_newConcat(&path, temp, name); + rtl_uString_release(temp); + temp = NULL; + + if (Options & osl_Pipe_CREATE) + { + SetLastError( ERROR_SUCCESS ); + + if ( IS_NT ) + pPipe->m_NamedObject = CreateMutexW( NULL, FALSE, name->buffer ); + else + { + LPSTR pszTempBuffer = NULL; + int nCharsNeeded; + + nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, name->buffer, name->length, NULL, 0, NULL, NULL ); + pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); + nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, name->buffer, name->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); + pszTempBuffer[nCharsNeeded-1] = 0; + + pPipe->m_NamedObject = CreateMutexA( NULL, FALSE, pszTempBuffer ); + } + + if ( pPipe->m_NamedObject != INVALID_HANDLE_VALUE && pPipe->m_NamedObject != NULL ) + { + if ( GetLastError() != ERROR_ALREADY_EXISTS ) + { + pPipe->m_Security = pSecAttr; + rtl_uString_assign(&pPipe->m_Name, name); + + if (IS_NT) + { + /* try to open system pipe */ + pPipe->m_File = CreateNamedPipeW( + path->buffer, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + PIPE_UNLIMITED_INSTANCES, + 4096, 4096, + NMPWAIT_WAIT_FOREVER, + pPipe->m_Security); + + if (pPipe->m_File != INVALID_HANDLE_VALUE) + { + rtl_uString_release( name ); + rtl_uString_release( path ); + + return pPipe; + } + } + else /* Win 9x */ + { + LPSTR pszTempBuffer = NULL; + int nCharsNeeded; + + nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, NULL, 0, NULL, NULL ); + pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); + nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); + pszTempBuffer[nCharsNeeded-1] = 0; + + pPipe->m_File = CreateSimplePipe( pszTempBuffer ); + + if ( IsValidHandle(pPipe->m_File) ) + { + rtl_uString_release( name ); + rtl_uString_release( path ); + + return pPipe; + } + } + } + else + { + CloseHandle( pPipe->m_NamedObject ); + pPipe->m_NamedObject = INVALID_HANDLE_VALUE; + } + } + } + else + { + if (IS_NT) + { + BOOL fPipeAvailable; + + do + { + /* free instance should be available first */ + fPipeAvailable = WaitNamedPipeW(path->buffer, NMPWAIT_WAIT_FOREVER); + + /* first try to open system pipe */ + if ( fPipeAvailable ) + { + pPipe->m_File = CreateFileW( + path->buffer, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + + if ( pPipe->m_File != INVALID_HANDLE_VALUE ) + { + // We got it ! + rtl_uString_release( name ); + rtl_uString_release( path ); + + return (pPipe); + } + else + { + // Pipe instance maybe catched by another client -> try again + } + } + } while ( fPipeAvailable ); + } + else /* Win 9x */ + { + LPSTR pszTempBuffer = NULL; + int nCharsNeeded; + + nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, NULL, 0, NULL, NULL ); + pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); + nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); + pszTempBuffer[nCharsNeeded-1] = 0; + + pPipe->m_File = OpenSimplePipe( pszTempBuffer ); + + if ( IsValidHandle(pPipe->m_File) ) + { + // We got it ! + rtl_uString_release( name ); + rtl_uString_release( path ); + + return (pPipe); + } + } + } + + /* if we reach here something went wrong */ + __osl_destroyPipeImpl(pPipe); + + return NULL; +} + +void SAL_CALL osl_acquirePipe( oslPipe pPipe ) +{ + osl_incrementInterlockedCount( &(pPipe->m_Reference) ); +} + +void SAL_CALL osl_releasePipe( oslPipe pPipe ) +{ +// OSL_ASSERT( pPipe ); + + if( 0 == pPipe ) + return; + + if( 0 == osl_decrementInterlockedCount( &(pPipe->m_Reference) ) ) + { + if( ! pPipe->m_bClosed ) + osl_closePipe( pPipe ); + + __osl_destroyPipeImpl( pPipe ); + } +} + +void SAL_CALL osl_closePipe( oslPipe pPipe ) +{ + if( pPipe && ! pPipe->m_bClosed ) + { + pPipe->m_bClosed = sal_True; + if (IS_NT) + { + /* if we have a system pipe close it */ + if (pPipe->m_File != INVALID_HANDLE_VALUE) + { + /* FlushFileBuffers(pPipe->m_File); */ + DisconnectNamedPipe(pPipe->m_File); + CloseHandle(pPipe->m_File); + } + } + else + { + CloseSimplePipe( pPipe->m_File ); + } + + } +} + +/*****************************************************************************/ +/* osl_acceptPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe) +{ + oslPipe pAcceptedPipe = NULL; + + HANDLE Event; + OVERLAPPED os; + + OSL_ASSERT(pPipe); + + if (IS_NT) + { + DWORD nBytesTransfered; + rtl_uString* path = NULL; + rtl_uString* temp = NULL; + + OSL_ASSERT (pPipe->m_File != INVALID_HANDLE_VALUE); + + Event = pPipe->m_AcceptEvent; + rtl_zeroMemory(&os, sizeof(OVERLAPPED)); + os.hEvent = pPipe->m_AcceptEvent; + ResetEvent(pPipe->m_AcceptEvent); + + if ( !ConnectNamedPipe(pPipe->m_File, &os)) + { + switch ( GetLastError() ) + { + case ERROR_PIPE_CONNECTED: // Client already connected to pipe + case ERROR_NO_DATA: // Client was connected but has already closed pipe end + // should only appear in nonblocking mode but in fact does + // in blocking asynchronous mode. + break; + case ERROR_PIPE_LISTENING: // Only for nonblocking mode but see ERROR_NO_DATA + case ERROR_IO_PENDING: // This is normal if not client is connected yet + case ERROR_MORE_DATA: // Should not happen + // blocking call to accept + if( !GetOverlappedResult( pPipe->m_File, &os, &nBytesTransfered, TRUE ) ) + { + // Possible error could be that between ConnectNamedPipe and GetOverlappedResult a connect + // took place. + + switch ( GetLastError() ) + { + case ERROR_PIPE_CONNECTED: // Pipe was already connected + case ERROR_NO_DATA: // Pipe was connected but client has already closed -> ver fast client ;-) + break; // Everything's fine !!! + default: + // Something went wrong + return 0; + } + } + break; + default: // All other error say that somethings going wrong. + return 0; + } + } + + + pAcceptedPipe = __osl_createPipeImpl(); + OSL_ASSERT(pAcceptedPipe); + + osl_incrementInterlockedCount(&(pAcceptedPipe->m_Reference)); + rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name); + pAcceptedPipe->m_File = pPipe->m_File; + + rtl_uString_newFromAscii(&temp, PIPESYSTEM); + rtl_uString_newConcat(&path, temp, pPipe->m_Name); + rtl_uString_release(temp); + + // prepare for next accept + pPipe->m_File = + CreateNamedPipeW(path->buffer, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + PIPE_UNLIMITED_INSTANCES, + 4096, 4096, + NMPWAIT_WAIT_FOREVER, + pAcceptedPipe->m_Security); + rtl_uString_release( path ); + } + else /* Win9x */ + { + pAcceptedPipe = __osl_createPipeImpl(); + OSL_ASSERT(pAcceptedPipe); + + osl_incrementInterlockedCount(&(pAcceptedPipe->m_Reference)); + rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name); + pAcceptedPipe->m_File = pPipe->m_File; + + pAcceptedPipe->m_File = AcceptSimplePipeConnection( pPipe->m_File ); + } + + return pAcceptedPipe; +} + +/*****************************************************************************/ +/* osl_receivePipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe, + void* pBuffer, + sal_Int32 BytesToRead) +{ + DWORD nBytes; + + OSL_ASSERT(pPipe); + + /* if we have a system pipe use it */ + if ( IS_NT /*pPipe->m_File != INVALID_HANDLE_VALUE*/) + { + OVERLAPPED os; + rtl_zeroMemory(&os,sizeof(OVERLAPPED)); + os.hEvent = pPipe->m_ReadEvent; + + ResetEvent(pPipe->m_ReadEvent); + + if (! ReadFile(pPipe->m_File, pBuffer, BytesToRead, &nBytes, &os) && + ((GetLastError() != ERROR_IO_PENDING) || + ! GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE))) + { + DWORD lastError = GetLastError(); + + if (lastError == ERROR_MORE_DATA) + nBytes = BytesToRead; + else + { + if (lastError == ERROR_PIPE_NOT_CONNECTED) + nBytes = 0; + else + nBytes = (DWORD) -1; + + pPipe->m_Error = osl_Pipe_E_ConnectionAbort; + } + } + } + else + { + BOOL fSuccess = ReadSimplePipe( pPipe->m_File, pBuffer, BytesToRead, &nBytes, TRUE ); + + if ( !fSuccess ) + { + nBytes = 0; + pPipe->m_Error = osl_Pipe_E_ConnectionAbort; + } + + } + + return (nBytes); +} + +/*****************************************************************************/ +/* osl_sendPipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe, + const void* pBuffer, + sal_Int32 BytesToSend) +{ + DWORD nBytes; + OSL_ASSERT(pPipe); + + if (IS_NT/*pPipe->m_File != INVALID_HANDLE_VALUE*/) + { + OVERLAPPED os; + rtl_zeroMemory(&os, sizeof(OVERLAPPED)); + os.hEvent = pPipe->m_WriteEvent; + ResetEvent(pPipe->m_WriteEvent); + + if (! WriteFile(pPipe->m_File, pBuffer, BytesToSend, &nBytes, &os) && + ((GetLastError() != ERROR_IO_PENDING) || + ! GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE))) + { + if (GetLastError() == ERROR_PIPE_NOT_CONNECTED) + nBytes = 0; + else + nBytes = (DWORD) -1; + + pPipe->m_Error = osl_Pipe_E_ConnectionAbort; + } + } + else + { + BOOL fSuccess = WriteSimplePipe( pPipe->m_File, pBuffer, BytesToSend, &nBytes, TRUE ); + + if ( !fSuccess ) + { + nBytes = 0; + pPipe->m_Error = osl_Pipe_E_ConnectionAbort; + } + } + + return (nBytes); +} + +sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n ) +{ + /* loop until all desired bytes were send or an error occured */ + sal_Int32 BytesSend= 0; + sal_Int32 BytesToSend= n; + + OSL_ASSERT(pPipe); + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToSend -= RetVal; + BytesSend += RetVal; + pBuffer= (sal_Char*)pBuffer + RetVal; + } + + return BytesSend; +} + +sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n ) +{ + /* loop until all desired bytes were read or an error occured */ + sal_Int32 BytesRead= 0; + sal_Int32 BytesToRead= n; + + OSL_ASSERT( pPipe ); + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToRead -= RetVal; + BytesRead += RetVal; + pBuffer= (sal_Char*)pBuffer + RetVal; + } + return BytesRead; +} + + +/*****************************************************************************/ +/* osl_getLastPipeError */ +/*****************************************************************************/ +oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe) +{ + oslPipeError Error; + + if (pPipe != NULL) + { + Error = pPipe->m_Error; + pPipe->m_Error = osl_Pipe_E_None; + } + else + Error = osl_Pipe_E_NotFound; + + return (Error); +} + diff --git a/sal/osl/w32/pipeimpl.cxx b/sal/osl/w32/pipeimpl.cxx new file mode 100644 index 000000000000..1d492115e8c5 --- /dev/null +++ b/sal/osl/w32/pipeimpl.cxx @@ -0,0 +1,785 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" +# include "pipeimpl.h" + +#ifndef _INC_MALLOC +# include <malloc.h> +#endif + +#ifndef _INC_TCHAR +# ifdef UNICODE +# define _UNICODE +# endif +# include <tchar.h> +#endif + +const TCHAR PIPE_NAME_PREFIX_MAPPING[] = TEXT("PIPE_FILE_MAPPING_"); +const TCHAR PIPE_NAME_PREFIX_SYNCHRONIZE[] = TEXT("PIPE_SYNCHRONIZE_MUTEX_"); +const TCHAR PIPE_NAME_PREFIX_CONNECTION[] = TEXT("PIPE_CONNECTION_SEMAPHORE_"); + +const DWORD PIPE_BUFFER_SIZE = 4096; + + +//============================================================================ +// PipeData +//============================================================================ + +struct PipeData +{ + DWORD dwProcessId; + HANDLE hReadPipe; + HANDLE hWritePipe; +}; + +//============================================================================ +// Pipe +//============================================================================ + +#ifdef UNICODE +#define Pipe PipeW +#define ClientPipe ClientPipeW +#define ServerPipe ServerPipeW +#else +#define Pipe PipeA +#define ClientPipe ClientPipeA +#define ServerPipe ServerPipeA +#endif + +class Pipe +{ +protected: + HANDLE m_hReadPipe; // Handle to use for reading + HANDLE m_hWritePipe; // Handle to use for writing + + Pipe( HANDLE hReadPipe, HANDLE hWritePipe ); + + static HANDLE CreatePipeDataMutex( LPCTSTR lpName, BOOL bInitialOwner ); + static HANDLE CreatePipeDataMapping( LPCTSTR lpName ); + static HANDLE OpenPipeDataMapping( LPCTSTR lpName ); + static HANDLE CreatePipeConnectionSemaphore( LPCTSTR lpName, LONG lInitialCount, LONG lMaximumcount ); + +public: + Pipe( const Pipe& ); + const Pipe& operator = ( const Pipe& ); + virtual ~Pipe(); + + virtual bool Close(); + virtual bool Write( LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, bool bWait = true ); + virtual bool Read( LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, bool bWait = true ); + + virtual Pipe *AcceptConnection() + { + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } + + void * operator new( size_t nBytes ) + { + return HeapAlloc( GetProcessHeap(), 0, nBytes ); + } + + void operator delete( void *ptr ) + { + HeapFree( GetProcessHeap(), 0, ptr ); + } + + bool is() const + { + return (FALSE != HeapValidate( GetProcessHeap(), 0, this )); + } + +}; + +//============================================================================ +// ClientPipe +//============================================================================ + +class ClientPipe : public Pipe +{ +protected: + ClientPipe( HANDLE hReadPipe, HANDLE hWritePipe ); +public: + static ClientPipe* Create( LPCTSTR lpName ); +}; + +//============================================================================ +// ServerPipe +//============================================================================ + +class ServerPipe : public Pipe +{ +protected: + HANDLE m_hMapping; + HANDLE m_hSynchronize; + LPTSTR m_lpName; + + ServerPipe( LPCTSTR lpName, HANDLE hMapping, HANDLE hSynchronize, HANDLE hReadPipe, HANDLE hWritePipe ); +public: + virtual ~ServerPipe(); + + static ServerPipe *Create( LPCTSTR lpName ); + + virtual Pipe *AcceptConnection(); +}; + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HANDLE Pipe::CreatePipeDataMapping( LPCTSTR lpName ) +{ + HANDLE hMapping = NULL; + LPTSTR lpMappingName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_MAPPING) ); + + if ( lpMappingName ) + { + _tcscpy( lpMappingName, PIPE_NAME_PREFIX_MAPPING ); + _tcscat( lpMappingName, lpName ); + + LPTSTR lpMappingFileName = (LPTSTR)alloca( MAX_PATH * sizeof(TCHAR) ); + + if ( lpMappingFileName ) + { + DWORD nChars = GetTempPath( MAX_PATH, lpMappingFileName ); + + if ( MAX_PATH + _tcslen(lpName) < nChars + 1 ) + { + lpMappingFileName = (LPTSTR)alloca( (nChars + 1 + _tcslen(lpName)) * sizeof(TCHAR) ); + if ( lpMappingFileName ) + nChars = GetTempPath( nChars, lpMappingFileName ); + else + { + nChars = 0; + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + } + } + + if ( nChars ) + { + _tcscat( lpMappingFileName, lpMappingName ); + + HANDLE hFile = CreateFile( + lpMappingFileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + NULL ); + + if ( IsValidHandle(hFile) ) + { + hMapping = CreateFileMapping( + (HANDLE)hFile, + (LPSECURITY_ATTRIBUTES)NULL, + PAGE_READWRITE, + 0, + sizeof(PipeData), + lpMappingName ); + + CloseHandle( hFile ); + } + } + } + else + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + } + + return hMapping; +} + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HANDLE Pipe::OpenPipeDataMapping( LPCTSTR lpName ) +{ + HANDLE hMapping = NULL; + LPTSTR lpMappingName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_MAPPING) ); + + if ( lpMappingName ) + { + _tcscpy( lpMappingName, PIPE_NAME_PREFIX_MAPPING ); + _tcscat( lpMappingName, lpName ); + + hMapping = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, lpMappingName ); + } + + return hMapping; +} + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HANDLE Pipe::CreatePipeDataMutex( LPCTSTR lpName, BOOL bInitialOwner ) +{ + HANDLE hMutex = NULL; + LPTSTR lpMutexName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_SYNCHRONIZE) ); + + if ( lpMutexName ) + { + _tcscpy( lpMutexName, PIPE_NAME_PREFIX_SYNCHRONIZE ); + _tcscat( lpMutexName, lpName ); + + hMutex = CreateMutex( NULL, bInitialOwner, lpMutexName ); + } + + return hMutex; +} + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HANDLE Pipe::CreatePipeConnectionSemaphore( LPCTSTR lpName, LONG lInitialCount, LONG lMaximumCount ) +{ + HANDLE hSemaphore = NULL; + LPTSTR lpSemaphoreName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_CONNECTION) ); + + if ( lpSemaphoreName ) + { + _tcscpy( lpSemaphoreName, PIPE_NAME_PREFIX_CONNECTION ); + _tcscat( lpSemaphoreName, lpName ); + + hSemaphore = CreateSemaphore( NULL, lInitialCount, lMaximumCount, lpSemaphoreName ); + } + + return hSemaphore; +} + + +//---------------------------------------------------------------------------- +// Pipe copy ctor +//---------------------------------------------------------------------------- + +Pipe::Pipe( const Pipe& rPipe ) : +m_hReadPipe( INVALID_HANDLE_VALUE ), +m_hWritePipe( INVALID_HANDLE_VALUE ) +{ + DuplicateHandle( + GetCurrentProcess(), + rPipe.m_hReadPipe, + GetCurrentProcess(), + &m_hReadPipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + DuplicateHandle( + GetCurrentProcess(), + rPipe.m_hWritePipe, + GetCurrentProcess(), + &m_hWritePipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); +} + +//---------------------------------------------------------------------------- +// Pipe assignment operator +//---------------------------------------------------------------------------- + +const Pipe& Pipe::operator = ( const Pipe& rPipe ) +{ + Close(); + + DuplicateHandle( + GetCurrentProcess(), + rPipe.m_hReadPipe, + GetCurrentProcess(), + &m_hReadPipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + DuplicateHandle( + GetCurrentProcess(), + rPipe.m_hWritePipe, + GetCurrentProcess(), + &m_hWritePipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + return *this; +} + +//---------------------------------------------------------------------------- +// Pipe ctor +//---------------------------------------------------------------------------- + +Pipe::Pipe( HANDLE hReadPipe, HANDLE hWritePipe ) : +m_hReadPipe( INVALID_HANDLE_VALUE ), +m_hWritePipe( INVALID_HANDLE_VALUE ) +{ + DuplicateHandle( + GetCurrentProcess(), + hReadPipe, + GetCurrentProcess(), + &m_hReadPipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + DuplicateHandle( + GetCurrentProcess(), + hWritePipe, + GetCurrentProcess(), + &m_hWritePipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); +} + +//---------------------------------------------------------------------------- +// Pipe dtor +//---------------------------------------------------------------------------- + +Pipe::~Pipe() +{ + Close(); +} + +//---------------------------------------------------------------------------- +// Pipe Close +//---------------------------------------------------------------------------- + +bool Pipe::Close() +{ + bool fSuccess = false; // Assume failure + + if ( IsValidHandle(m_hReadPipe) ) + { + CloseHandle( m_hReadPipe ); + m_hReadPipe = INVALID_HANDLE_VALUE; + } + + if ( IsValidHandle(m_hWritePipe) ) + { + CloseHandle( m_hWritePipe ); + m_hWritePipe = INVALID_HANDLE_VALUE; + } + + return fSuccess; +} + +//---------------------------------------------------------------------------- +// Pipe Write +//---------------------------------------------------------------------------- + +bool Pipe::Write( LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, bool bWait ) +{ + DWORD dwBytesAvailable = 0; + BOOL fSuccess = TRUE; + + if ( !bWait ) + fSuccess = PeekNamedPipe( m_hReadPipe, NULL, 0, NULL, &dwBytesAvailable, NULL ); + + if ( fSuccess ) + { + if ( !bWait && dwBytesToWrite > PIPE_BUFFER_SIZE - dwBytesAvailable ) + dwBytesToWrite = PIPE_BUFFER_SIZE - dwBytesAvailable ; + + return !!WriteFile( m_hWritePipe, lpBuffer, dwBytesToWrite, lpBytesWritten, NULL ); + } + + return false; +} + +//---------------------------------------------------------------------------- +// Pipe Read +//---------------------------------------------------------------------------- + +bool Pipe::Read( LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, bool bWait ) +{ + DWORD dwBytesAvailable = 0; + BOOL fSuccess = TRUE; + + if ( !bWait ) + fSuccess = PeekNamedPipe( m_hReadPipe, NULL, 0, NULL, &dwBytesAvailable, NULL ); + + if ( fSuccess ) + { + if ( bWait || dwBytesAvailable ) + return !!ReadFile( m_hReadPipe, lpBuffer, dwBytesToRead, lpBytesRead, NULL ); + else + { + *lpBytesRead = 0; + return true; + } + } + + return false; +} + + + +//---------------------------------------------------------------------------- +// Client pipe dtor +//---------------------------------------------------------------------------- + +ClientPipe::ClientPipe( HANDLE hReadPipe, HANDLE hWritePipe ) : Pipe( hReadPipe, hWritePipe ) +{ +} + +//---------------------------------------------------------------------------- +// Client pipe creation +//---------------------------------------------------------------------------- + +ClientPipe *ClientPipe::Create( LPCTSTR lpName ) +{ + ClientPipe *pPipe = NULL; // Assume failure + + HANDLE hMapping = OpenPipeDataMapping( lpName ); + + if ( IsValidHandle(hMapping) ) + { + PipeData *pData = (PipeData*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); + + if ( pData ) + { + HANDLE hSourceProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, pData->dwProcessId ); + + if ( IsValidHandle(hSourceProcess) ) + { + BOOL fSuccess; + HANDLE hReadPipe = INVALID_HANDLE_VALUE, hWritePipe = INVALID_HANDLE_VALUE; + + fSuccess = DuplicateHandle( + hSourceProcess, + pData->hReadPipe, + GetCurrentProcess(), + &hReadPipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + fSuccess = fSuccess && DuplicateHandle( + hSourceProcess, + pData->hWritePipe, + GetCurrentProcess(), + &hWritePipe, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + if ( fSuccess ) + pPipe = new ClientPipe( hReadPipe, hWritePipe ); + + if ( IsValidHandle(hWritePipe) ) + CloseHandle( hWritePipe ); + + if ( IsValidHandle(hReadPipe) ) + CloseHandle( hReadPipe ); + + HANDLE hConnectionRequest = CreatePipeConnectionSemaphore( lpName, 0, 1 ); + + ReleaseSemaphore( hConnectionRequest, 1, NULL ); + + CloseHandle( hConnectionRequest ); + + CloseHandle( hSourceProcess ); + } + + UnmapViewOfFile( pData ); + } + + CloseHandle( hMapping ); + } + + return pPipe; +} + + + +//---------------------------------------------------------------------------- +// ServerPipe ctor +//---------------------------------------------------------------------------- + +ServerPipe::ServerPipe( LPCTSTR lpName, HANDLE hMapping, HANDLE hSynchronize, HANDLE hReadPipe, HANDLE hWritePipe ) : Pipe( hReadPipe, hWritePipe ), +m_hMapping( NULL ), +m_hSynchronize( NULL ), +m_lpName( NULL ) +{ + DuplicateHandle( + GetCurrentProcess(), + hMapping, + GetCurrentProcess(), + &m_hMapping, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ); + + DuplicateHandle( + GetCurrentProcess(), + hSynchronize, + GetCurrentProcess(), + &m_hSynchronize, + 0, + FALSE, + DUPLICATE_SAME_ACCESS + ); + m_lpName = new TCHAR[_tcslen(lpName) + 1]; + if ( m_lpName ) + _tcscpy( m_lpName, lpName ); +} + +//---------------------------------------------------------------------------- +// ServerPipe dtor +//---------------------------------------------------------------------------- + +ServerPipe::~ServerPipe() +{ + if ( IsValidHandle(m_hMapping) ) + CloseHandle( m_hMapping ); + if ( m_lpName ) + delete[]m_lpName; +} + +//---------------------------------------------------------------------------- +// ServerPipe AcceptConnection +//---------------------------------------------------------------------------- + +Pipe *ServerPipe::AcceptConnection() +{ + Pipe *pPipe = NULL; // Assume failure; + + HANDLE hConnectionRequest = CreatePipeConnectionSemaphore( m_lpName, 0, 1 ); + + if ( WAIT_OBJECT_0 == WaitForSingleObject( hConnectionRequest, INFINITE ) ) + { + pPipe = new Pipe( *this ); + Close(); + + // Create new inbound Pipe + + HANDLE hClientWritePipe = NULL, hServerReadPipe = NULL; + + BOOL fSuccess = CreatePipe( &hServerReadPipe, &hClientWritePipe, NULL, PIPE_BUFFER_SIZE ); + + + if ( fSuccess ) + { + // Create outbound pipe + + HANDLE hClientReadPipe = NULL, hServerWritePipe = NULL; + + if ( CreatePipe( &hClientReadPipe, &hServerWritePipe, NULL, PIPE_BUFFER_SIZE ) ) + { + m_hReadPipe = hServerReadPipe; + m_hWritePipe = hServerWritePipe; + + PipeData *pData = (PipeData *)MapViewOfFile( m_hMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(PipeData) ); + + HANDLE hSynchronize = CreatePipeDataMutex( m_lpName, TRUE ); + + CloseHandle( pData->hReadPipe ); + CloseHandle( pData->hWritePipe ); + + pData->hReadPipe = hClientReadPipe; + pData->hWritePipe = hClientWritePipe; + + ReleaseMutex( hSynchronize ); + + CloseHandle( hSynchronize ); + + } + else + { + CloseHandle( hClientWritePipe ); + CloseHandle( hServerWritePipe ); + } + } + + ReleaseMutex( hConnectionRequest ); + } + + CloseHandle( hConnectionRequest ); + + return pPipe; +} + +//---------------------------------------------------------------------------- +// Pipe creation +//---------------------------------------------------------------------------- + +ServerPipe *ServerPipe::Create( LPCTSTR lpName ) +{ + ServerPipe *pPipe = NULL; + + HANDLE hMapping = CreatePipeDataMapping( lpName ); + + if ( IsValidHandle(hMapping) ) + { + if ( ERROR_FILE_EXISTS != GetLastError() ) + { + HANDLE hSynchronize = CreatePipeDataMutex( lpName, FALSE); + + WaitForSingleObject( hSynchronize, INFINITE ); + + PipeData *pData = (PipeData*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); + + if ( pData ) + { + + // Initialize pipe data + + pData->dwProcessId = 0; + pData->hReadPipe = NULL; + pData->hWritePipe = NULL; + + // Create inbound pipe + + HANDLE hServerReadPipe = NULL, hClientWritePipe = NULL; + + BOOL fSuccess = CreatePipe( &hServerReadPipe, &hClientWritePipe, NULL, PIPE_BUFFER_SIZE ); + + if ( fSuccess ) + { + // Create outbound pipe + + HANDLE hServerWritePipe = NULL, hClientReadPipe = NULL; + + fSuccess = CreatePipe( &hClientReadPipe, &hServerWritePipe, NULL, PIPE_BUFFER_SIZE ); + + if ( fSuccess ) + { + pData->dwProcessId = GetCurrentProcessId(); + pData->hReadPipe = hClientReadPipe; + pData->hWritePipe = hClientWritePipe; + pPipe = new ServerPipe( lpName, hMapping, hSynchronize, hServerReadPipe, hServerWritePipe ); + + CloseHandle( hServerWritePipe ); + CloseHandle( hServerReadPipe ); + } + else + { + CloseHandle( hServerReadPipe ); + CloseHandle( hClientWritePipe ); + } + } + + UnmapViewOfFile( pData ); + } + + ReleaseMutex( hSynchronize ); + CloseHandle( hSynchronize ); + } + + CloseHandle( hMapping ); + } + + return pPipe; +} + + +//---------------------------------------------------------------------------- +// C style API +//---------------------------------------------------------------------------- + +const TCHAR LOCAL_PIPE_PREFIX[] = TEXT("\\\\.\\PIPE\\" ); + +extern "C" HANDLE WINAPI CreateSimplePipe( LPCTSTR lpName ) +{ + int nPrefixLen = _tcslen( LOCAL_PIPE_PREFIX ); + if ( 0 == _tcsnicmp( lpName, LOCAL_PIPE_PREFIX, nPrefixLen ) ) + lpName += nPrefixLen; + return (HANDLE)ServerPipe::Create( lpName ); +} + +extern "C" HANDLE WINAPI OpenSimplePipe( LPCTSTR lpName ) +{ + int nPrefixLen = _tcslen( LOCAL_PIPE_PREFIX ); + if ( 0 == _tcsnicmp( lpName, LOCAL_PIPE_PREFIX, nPrefixLen ) ) + lpName += nPrefixLen; + return (HANDLE)ClientPipe::Create( lpName ); +} + +extern "C" HANDLE WINAPI AcceptSimplePipeConnection( HANDLE hPipe ) +{ + Pipe *pPipe = (Pipe *)hPipe; + + if ( pPipe->is() ) + return (HANDLE)pPipe->AcceptConnection(); + else + { + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } +} + +extern "C" BOOL WINAPI WaitForSimplePipe( LPCTSTR /*lpName*/, DWORD /*dwTimeOut*/ ) +{ + return FALSE; +} + +extern "C" BOOL WINAPI WriteSimplePipe( HANDLE hPipe, LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, BOOL bWait ) +{ + Pipe *pPipe = (Pipe *)hPipe; + + if ( pPipe->is() ) + return pPipe->Write( lpBuffer, dwBytesToWrite, lpBytesWritten, bWait ); + else + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } +} + +extern "C" BOOL WINAPI ReadSimplePipe( HANDLE hPipe, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, BOOL bWait ) +{ + Pipe *pPipe = (Pipe *)hPipe; + + if ( pPipe->is() ) + return pPipe->Read( lpBuffer, dwBytesToRead, lpBytesRead, bWait ); + else + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } +} + +extern "C" BOOL WINAPI CloseSimplePipe( HANDLE hPipe ) +{ + Pipe *pPipe = (Pipe *)hPipe; + + if ( pPipe->is() ) + { + delete pPipe; + return TRUE; + } + else + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } +} diff --git a/sal/osl/w32/pipeimpl.h b/sal/osl/w32/pipeimpl.h new file mode 100644 index 000000000000..83f678f6c49d --- /dev/null +++ b/sal/osl/w32/pipeimpl.h @@ -0,0 +1,88 @@ +#ifndef _PIPEIMPL_H_ +#define _PIPEIMPL_H_ + +#ifndef _WINDOWS_ +# ifdef _MSC_VER +# pragma warning(push,1) /* disable warnings within system headers */ +# endif +# include <windows.h> +# ifdef _MSC_VER +# pragma warning(pop) +# endif +#endif + +#ifndef _INC_MALLOC +# include <malloc.h> +#endif + +#ifndef _INC_TCHAR +# ifdef UNICODE +# define _UNICODE +# endif +# include <tchar.h> +#endif + +#define EXPORT_PIPE_API + +//============================================================================ +// Helper functions +//============================================================================ + +// Because the value of an invalid HANDLE returned by API functions differs +// between different functions and differs on different Windows platforms, +// this function checks wether the handle has a meaningfull value. +#ifndef __cplusplus + +#define IsValidHandle( handle ) ((DWORD)(handle) + 1 > 1) + +#else + +inline bool IsValidHandle( HANDLE handle ) +{ + return INVALID_HANDLE_VALUE != handle && NULL != handle; +} + +extern "C" { + +#endif // __cplusplus + + +EXPORT_PIPE_API HANDLE WINAPI CreateSimplePipeA( LPCSTR lpName ); +EXPORT_PIPE_API HANDLE WINAPI CreateSimplePipeW( LPCWSTR lpName ); + +#ifdef UNICODE +#define CreateSimplePipe CreateSimplePipeW +#else +#define CreateSimplePipe CreateSimplePipeA +#endif + +EXPORT_PIPE_API HANDLE WINAPI OpenSimplePipeA( LPCSTR lpName ); +EXPORT_PIPE_API HANDLE WINAPI OpenSimplePipeW( LPCWSTR lpName ); + +#ifdef UNICODE +#define OpenSimplePipe OpenSimplePipeW +#else +#define OpenSimplePipe OpenSimplePipeA +#endif + +EXPORT_PIPE_API HANDLE WINAPI AcceptSimplePipeConnection( HANDLE hPipe ); + +EXPORT_PIPE_API BOOL WINAPI WaitForSimplePipeA( LPCSTR lpName, DWORD dwTimeOut ); +EXPORT_PIPE_API BOOL WINAPI WaitForSimplePipeW( LPCWSTR lpName, DWORD dwTimeOut ); + +#ifdef UNICODE +#define WaitForSimplePipe WaitForSimplePipeW +#else +#define WaitForSimplePipe WaitForSimplePipeA +#endif + + +EXPORT_PIPE_API BOOL WINAPI WriteSimplePipe( HANDLE hPipe, LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, BOOL bWait ); +EXPORT_PIPE_API BOOL WINAPI ReadSimplePipe( HANDLE hPipe, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, BOOL bWait ); +EXPORT_PIPE_API BOOL WINAPI CloseSimplePipe( HANDLE hPipe ); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PIPEIMPL_H_ diff --git a/sal/osl/w32/process.cxx b/sal/osl/w32/process.cxx new file mode 100644 index 000000000000..96187be7e203 --- /dev/null +++ b/sal/osl/w32/process.cxx @@ -0,0 +1,620 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2010 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#define UNICODE +#include "system.h" +#ifdef _MSC_VER +#pragma warning(push,1) /* disable warnings within system headers */ +#endif +#include <shellapi.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include <osl/diagnose.h> +#include <osl/security.h> +#include <osl/nlsupport.h> +#include <osl/mutex.h> +#include <osl/thread.h> + +#include "procimpl.h" +#include "sockimpl.h" +#include "file_url.h" +#include "path_helper.hxx" +#include <rtl/ustrbuf.h> +#include <rtl/alloc.h> + +/*************************************************************************** + * Process. + ***************************************************************************/ + +oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process) +{ + if (Process == NULL) + return osl_Process_E_Unknown; + + if (TerminateProcess(((oslProcessImpl*)Process)->m_hProcess, 0)) + return osl_Process_E_None; + + + return osl_Process_E_Unknown; +} + +/***************************************************************************/ + +oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident) +{ + oslProcessImpl* pProcImpl; + HANDLE hProcess = OpenProcess( + STANDARD_RIGHTS_REQUIRED | PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, (DWORD)Ident); + + if (hProcess) + { + pProcImpl = reinterpret_cast< oslProcessImpl*>( rtl_allocateMemory(sizeof(oslProcessImpl)) ); + pProcImpl->m_hProcess = hProcess; + pProcImpl->m_IdProcess = Ident; + } + else + pProcImpl = NULL; + + return (pProcImpl); +} + +/***************************************************************************/ + +void SAL_CALL osl_freeProcessHandle(oslProcess Process) +{ + if (Process != NULL) + { + CloseHandle(((oslProcessImpl*)Process)->m_hProcess); + + rtl_freeMemory((oslProcessImpl*)Process); + } +} + +/***************************************************************************/ + +oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, + oslProcessInfo* pInfo) +{ + HANDLE hProcess; + DWORD IdProcess; + + if (Process == NULL) + { + hProcess = GetCurrentProcess(); + IdProcess = GetCurrentProcessId(); + } + else + { + hProcess = ((oslProcessImpl*)Process)->m_hProcess; + IdProcess = ((oslProcessImpl*)Process)->m_IdProcess; + } + + if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo))) + return osl_Process_E_Unknown; + + pInfo->Fields = 0; + + if (Fields & osl_Process_IDENTIFIER) + { + pInfo->Ident = IdProcess; + pInfo->Fields |= osl_Process_IDENTIFIER; + } + + if (Fields & osl_Process_EXITCODE) + { + if (GetExitCodeProcess(hProcess, &(pInfo->Code)) && (pInfo->Code != STILL_ACTIVE)) + pInfo->Fields |= osl_Process_EXITCODE; + } + + if (Fields & osl_Process_HEAPUSAGE) + { + void* lpAddress=0; + MEMORY_BASIC_INFORMATION Info; + + pInfo->HeapUsage = 0; + + do + { + if (VirtualQueryEx(hProcess, lpAddress, &Info, sizeof(Info)) == 0) + break; + + if ((Info.State == MEM_COMMIT) && (Info.Type == MEM_PRIVATE)) + pInfo->HeapUsage += Info.RegionSize; + + lpAddress = (LPBYTE)lpAddress + Info.RegionSize; + } + while (lpAddress < (void *)0x80000000); // 2GB address space + + pInfo->Fields |= osl_Process_HEAPUSAGE; + } + + if (Fields & osl_Process_CPUTIMES) + { + FILETIME CreationTime, ExitTime, KernelTime, UserTime; + + if (GetProcessTimes(hProcess, &CreationTime, &ExitTime, + &KernelTime, &UserTime)) + { + __int64 Value; + + Value = *((__int64 *)&UserTime); + pInfo->UserTime.Seconds = (unsigned long) (Value / 10000000L); + pInfo->UserTime.Nanosec = (unsigned long)((Value % 10000000L) * 100); + + Value = *((__int64 *)&KernelTime); + pInfo->SystemTime.Seconds = (unsigned long) (Value / 10000000L); + pInfo->SystemTime.Nanosec = (unsigned long)((Value % 10000000L) * 100); + + pInfo->Fields |= osl_Process_CPUTIMES; + } + } + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; +} + +/***************************************************************************/ + +oslProcessError SAL_CALL osl_joinProcess(oslProcess Process) +{ + return osl_joinProcessWithTimeout(Process, NULL); +} + +/***************************************************************************/ + +oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout) +{ + DWORD timeout = INFINITE; + oslProcessError osl_error = osl_Process_E_None; + DWORD ret; + + if (NULL == Process) + return osl_Process_E_Unknown; + + if (pTimeout) + timeout = pTimeout->Seconds * 1000 + pTimeout->Nanosec / 1000000L; + + ret = WaitForSingleObject(((oslProcessImpl*)Process)->m_hProcess, timeout); + + if (WAIT_FAILED == ret) + osl_error = osl_Process_E_Unknown; + else if (WAIT_TIMEOUT == ret) + osl_error = osl_Process_E_TimedOut; + + return osl_error; +} + +/*************************************************************************** + * osl_bootstrap_getExecutableFile_Impl(). + * + * @internal + * @see rtl_bootstrap + * @see #i37371# + * + ***************************************************************************/ + +extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C() +{ + oslProcessError result = osl_Process_E_NotFound; + + ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); + DWORD buflen = 0; + + if ((buflen = GetModuleFileNameW (0, ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), aBuffer.getBufSizeInSymbols())) > 0) + { + rtl_uString * pAbsPath = 0; + rtl_uString_newFromStr_WithLength (&(pAbsPath), aBuffer, buflen); + if (pAbsPath) + { + /* Convert from path to url. */ + if (osl_getFileURLFromSystemPath (pAbsPath, ppFileURL) == osl_File_E_None) + { + /* Success. */ + result = osl_Process_E_None; + } + rtl_uString_release (pAbsPath); + } + } + + return (result); +} + +/*************************************************************************** + * Command Line Arguments. + ***************************************************************************/ + +struct CommandArgs_Impl +{ + sal_uInt32 m_nCount; + rtl_uString ** m_ppArgs; +}; + +static struct CommandArgs_Impl g_command_args = +{ + 0, + 0 +}; + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable: 4100 ) +#endif +static rtl_uString ** osl_createCommandArgs_Impl (int argc, char ** argv) +{ + rtl_uString ** ppArgs = + (rtl_uString**)rtl_allocateZeroMemory (argc * sizeof(rtl_uString*)); + if (ppArgs != 0) + { + int i; + int nArgs; + LPWSTR *wargv = CommandLineToArgvW( GetCommandLineW(), &nArgs ); + OSL_ASSERT( nArgs == argc ); + for (i = 0; i < nArgs; i++) + { + /* Convert to unicode */ + rtl_uString_newFromStr( &(ppArgs[i]), reinterpret_cast<const sal_Unicode*>(wargv[i]) ); + } + if (ppArgs[0] != 0) + { + /* Ensure absolute path */ + ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); + DWORD dwResult = 0; + + dwResult = SearchPath ( + 0, reinterpret_cast<LPCWSTR>(ppArgs[0]->buffer), L".exe", aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), 0); + if ((0 < dwResult) && (dwResult < aBuffer.getBufSizeInSymbols())) + { + /* Replace argv[0] with it's absolute path */ + rtl_uString_newFromStr_WithLength( + &(ppArgs[0]), aBuffer, dwResult); + } + } + if (ppArgs[0] != 0) + { + /* Convert to FileURL, see @ osl_getExecutableFile() */ + rtl_uString * pResult = 0; + osl_getFileURLFromSystemPath (ppArgs[0], &pResult); + if (pResult != 0) + { + rtl_uString_assign (&(ppArgs[0]), pResult); + rtl_uString_release (pResult); + } + } + } + return (ppArgs); + +} +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +/***************************************************************************/ + +oslProcessError SAL_CALL osl_getExecutableFile( rtl_uString **ppustrFile ) +{ + oslProcessError result = osl_Process_E_NotFound; + + osl_acquireMutex (*osl_getGlobalMutex()); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > 0) + { + /* CommandArgs set. Obtain arv[0]. */ + rtl_uString_assign (ppustrFile, g_command_args.m_ppArgs[0]); + result = osl_Process_E_None; + } + osl_releaseMutex (*osl_getGlobalMutex()); + + return (result); +} + +/***************************************************************************/ + +sal_uInt32 SAL_CALL osl_getCommandArgCount(void) +{ + sal_uInt32 result = 0; + + osl_acquireMutex (*osl_getGlobalMutex()); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > 0) + { + /* We're not counting argv[0] here. */ + result = g_command_args.m_nCount - 1; + } + osl_releaseMutex (*osl_getGlobalMutex()); + + return (result); +} + +/***************************************************************************/ + +oslProcessError SAL_CALL osl_getCommandArg( sal_uInt32 nArg, rtl_uString **strCommandArg) +{ + oslProcessError result = osl_Process_E_NotFound; + + osl_acquireMutex (*osl_getGlobalMutex()); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > (nArg + 1)) + { + /* We're not counting argv[0] here. */ + rtl_uString_assign (strCommandArg, g_command_args.m_ppArgs[nArg + 1]); + result = osl_Process_E_None; + } + osl_releaseMutex (*osl_getGlobalMutex()); + + return (result); +} + +/***************************************************************************/ + +void SAL_CALL osl_setCommandArgs (int argc, char ** argv) +{ + OSL_ASSERT(argc > 0); + osl_acquireMutex (*osl_getGlobalMutex()); + if (g_command_args.m_nCount == 0) + { + rtl_uString** ppArgs = osl_createCommandArgs_Impl (argc, argv); + if (ppArgs != 0) + { + g_command_args.m_nCount = argc; + g_command_args.m_ppArgs = ppArgs; + } + } + osl_releaseMutex (*osl_getGlobalMutex()); +} + +/*************************************************************************** + * Environment + ***************************************************************************/ +/* + #109941# because of a bug in the M$ unicows library we have to + allocate a buffer large enough to hold the requested environment + variable instead of testing for the required size. This wastes + some stack space, maybe we should revoke this work around if + unicows library is fixed. +*/ +#define ENV_BUFFER_SIZE (32*1024-1) + +oslProcessError SAL_CALL osl_getEnvironment(rtl_uString *ustrVar, rtl_uString **ustrValue) +{ + WCHAR buff[ENV_BUFFER_SIZE]; + + if (GetEnvironmentVariableW(reinterpret_cast<LPCWSTR>(ustrVar->buffer), buff, ENV_BUFFER_SIZE) > 0) + { + rtl_uString_newFromStr(ustrValue, reinterpret_cast<const sal_Unicode*>(buff)); + return osl_Process_E_None; + } + return osl_Process_E_Unknown; +} + +/*************************************************************************** + * Current Working Directory. + ***************************************************************************/ + +extern "C" oslMutex g_CurrentDirectoryMutex; + +oslProcessError SAL_CALL osl_getProcessWorkingDir( rtl_uString **pustrWorkingDir ) +{ + ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); + DWORD dwLen = 0; + + + osl_acquireMutex( g_CurrentDirectoryMutex ); + dwLen = GetCurrentDirectory( aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer) ); + osl_releaseMutex( g_CurrentDirectoryMutex ); + + if ( dwLen && dwLen < aBuffer.getBufSizeInSymbols() ) + { + oslFileError eError; + rtl_uString *ustrTemp = NULL;; + + rtl_uString_newFromStr_WithLength( &ustrTemp, aBuffer, dwLen ); + eError = osl_getFileURLFromSystemPath( ustrTemp, pustrWorkingDir ); + + rtl_uString_release( ustrTemp ); + + if ( osl_File_E_None != eError ) + return osl_Process_E_Unknown; + else + return osl_Process_E_None; + } + else + return osl_Process_E_Unknown; +} + +/*************************************************************************** + * Process Locale. + ***************************************************************************/ + +extern "C" void _imp_getProcessLocale( rtl_Locale ** ppLocale ); + +static rtl_Locale * g_theProcessLocale = NULL; + +/***************************************************************************/ + +oslProcessError SAL_CALL osl_getProcessLocale( rtl_Locale ** ppLocale ) +{ + osl_acquireMutex( *osl_getGlobalMutex() ); + + /* determine the users default locale */ + if( NULL == g_theProcessLocale ) + _imp_getProcessLocale( &g_theProcessLocale ); + + /* or return the cached value */ + *ppLocale = g_theProcessLocale; + + osl_releaseMutex( *osl_getGlobalMutex() ); + return osl_Process_E_None; +} + +/***************************************************************************/ + +oslProcessError SAL_CALL osl_setProcessLocale( rtl_Locale * pLocale ) +{ + osl_acquireMutex( *osl_getGlobalMutex() ); + + /* check if locale is supported */ + if( RTL_TEXTENCODING_DONTKNOW == osl_getTextEncodingFromLocale( pLocale ) ) + return osl_Process_E_Unknown; + + /* just remember the locale here */ + g_theProcessLocale = pLocale; + + osl_releaseMutex( *osl_getGlobalMutex() ); + return osl_Process_E_None; +} + +/************************************************ + * Portal send/receive interface implementation + ************************************************/ + +static sal_Bool ReadPipe(oslPipe hPipe, + void* pBuffer, + sal_Int32 BytesToRead, + sal_Int32* nBytes) +{ + *nBytes = osl_receivePipe(hPipe, pBuffer, BytesToRead); + OSL_TRACE("tried to recieve %d, recieved %d.\n", + BytesToRead, *nBytes); + return (sal_Bool)((*nBytes >= 0) && (osl_getLastPipeError(hPipe) == osl_Pipe_E_None)); +} + +static sal_Bool WritePipe(oslPipe hPipe, + void* pBuffer, + sal_Int32 BytesToSend, + sal_Int32* nBytes) +{ + *nBytes = osl_sendPipe(hPipe, pBuffer, BytesToSend); + OSL_TRACE("tried to send %d, sent %d\n", + BytesToSend, *nBytes); + return (sal_Bool)((*nBytes == BytesToSend) && (osl_getLastPipeError(hPipe) == osl_Pipe_E_None)); +} + +sal_Bool SAL_CALL osl_sendResourcePipe(oslPipe hPipe, oslSocket pSocket) +{ + sal_Bool bRet = sal_False; + sal_Int32 bytes = 0; + + /* duplicate handle on this other side -> + receive remote process + duplicate handle and send it */ + DWORD remoteProcessID = 0; + HANDLE fd = (HANDLE)pSocket->m_Socket; + oslDescriptorType code = osl_Process_TypeSocket; + + OSL_TRACE("osl_sendResourcePipe: enter..."); + + if (ReadPipe(hPipe, &remoteProcessID, sizeof(remoteProcessID), &bytes)) + { + HANDLE hRemoteProc = OpenProcess(PROCESS_DUP_HANDLE, + FALSE, + remoteProcessID); + + if (hRemoteProc != (HANDLE)NULL) + { + HANDLE newFd; + + if (DuplicateHandle(GetCurrentProcess(), + fd, + hRemoteProc, + &newFd, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + if ( + WritePipe(hPipe, &code, sizeof(code), &bytes) && + WritePipe(hPipe, &newFd, sizeof(fd), &bytes) + ) + bRet = sal_True; + } + + CloseHandle(hRemoteProc); + } + } + + if (bRet) + { + sal_Int32 commitCode; + OSL_TRACE("osl_sendResourcePipe: handle sent successfully, verify...\n"); + + if ( + !ReadPipe(hPipe, &commitCode, sizeof(commitCode), &bytes) || + (commitCode <= 0) + ) + bRet = sal_False; + } + + OSL_TRACE("osl_sendResourcePipe: exit... %d\n", bRet); + return(bRet); +} + + +oslSocket SAL_CALL osl_receiveResourcePipe(oslPipe hPipe) +{ + sal_Bool bRet = sal_False; + sal_Int32 bytes = 0; + sal_Int32 commitCode; + oslSocket pSocket = NULL; + + /* duplicate handle on the other side -> + send my process id receive duplicated handle */ + HANDLE fd = INVALID_HANDLE_VALUE; + DWORD myProcessID = GetCurrentProcessId(); + oslDescriptorType code = osl_Process_TypeNone; + + OSL_TRACE("osl_receiveResourcePipe: enter...\n"); + + if ( + WritePipe(hPipe, &myProcessID, sizeof(myProcessID), &bytes) && + ReadPipe(hPipe, &code, sizeof(code), &bytes) && + ReadPipe(hPipe, &fd, sizeof(fd), &bytes) + ) + { + if (code == osl_Process_TypeSocket) + { + pSocket = __osl_createSocketImpl((SOCKET)fd); + bRet = sal_True; + } + else + { + OSL_TRACE("osl_receiveResourcePipe: UKNOWN\n"); + bRet = sal_False; + } + } + + if (bRet) + commitCode = 1; + else + commitCode = 0; + + WritePipe(hPipe, &commitCode, sizeof(commitCode), &bytes); + + OSL_TRACE("osl_receiveResourcePipe: exit... %d, %p\n", bRet, pSocket); + + return pSocket; +} diff --git a/sal/osl/w32/procimpl.cxx b/sal/osl/w32/procimpl.cxx new file mode 100644 index 000000000000..fc04d5b84a8f --- /dev/null +++ b/sal/osl/w32/procimpl.cxx @@ -0,0 +1,606 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#define UNICODE +#define _UNICODE + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# ifdef _MSC_VER +# pragma warning(push,1) /* disable warnings within system headers */ +# endif +# include <windows.h> +# ifdef _MSC_VER +# pragma warning(pop) +# endif +# include <tchar.h> +# undef WIN32_LEAN_AND_MEAN +#endif +#include "procimpl.h" +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include "secimpl.h" +#include "rtl/allocator.hxx" +#include <osl/file.hxx> + +#include <list> +#include <vector> +#include <algorithm> +#include <string> + +//################################################# +extern "C" oslFileHandle SAL_CALL osl_createFileHandleFromOSHandle( HANDLE hFile, sal_uInt32 uFlags ); + +//################################################# +const sal_Unicode NAME_VALUE_SEPARATOR = TEXT('='); +const sal_Char* SPACE = " "; +const rtl::OUString ENV_COMSPEC = rtl::OUString::createFromAscii("COMSPEC"); +const rtl::OUString QUOTE = rtl::OUString::createFromAscii("\""); + +namespace /* private */ +{ + //################################################# + typedef std::list<rtl::OUString, rtl::Allocator<rtl::OUString> > string_container_t; + typedef string_container_t::iterator string_container_iterator_t; + typedef string_container_t::const_iterator string_container_const_iterator_t; + typedef std::pair<string_container_iterator_t, string_container_iterator_t> iterator_pair_t; + typedef std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > environment_container_t; + + //################################################# + /* Function object that compares two strings that are + expected to be environment variables in the form + "name=value". Only the 'name' part will be compared. + The comparison is in upper case and returns true + if the first of both strings is less than the + second one. */ + struct less_environment_variable : + public std::binary_function<rtl::OUString, rtl::OUString, bool> + { + bool operator() (const rtl::OUString& lhs, const rtl::OUString& rhs) const + { + OSL_ENSURE((lhs.indexOf(NAME_VALUE_SEPARATOR) > -1) && \ + (rhs.indexOf(NAME_VALUE_SEPARATOR) > -1), \ + "Malformed environment variable"); + + // Windows compares environment variables uppercase + // so we do it, too + return (rtl_ustr_compare_WithLength( + lhs.toAsciiUpperCase().pData->buffer, + lhs.indexOf(NAME_VALUE_SEPARATOR), + rhs.toAsciiUpperCase().pData->buffer, + rhs.indexOf(NAME_VALUE_SEPARATOR)) < 0); + } + }; + + //################################################# + /* Function object used by for_each algorithm to + calculate the sum of the length of all strings + in a string container. */ + class sum_of_string_lengths + { + public: + //-------------------------------- + sum_of_string_lengths() : sum_(0) {} + + //-------------------------------- + void operator() (const rtl::OUString& string) + { + OSL_ASSERT(string.getLength()); + + // always include the terminating '\0' + if (string.getLength()) + sum_ += string.getLength() + 1; + } + + //-------------------------------- + operator size_t () const + { + return sum_; + } + private: + size_t sum_; + }; + + //################################################# + inline size_t calc_sum_of_string_lengths(const string_container_t& string_cont) + { + return std::for_each( + string_cont.begin(), string_cont.end(), sum_of_string_lengths()); + } + + //################################################# + void read_environment(/*out*/ string_container_t* environment) + { + // GetEnvironmentStrings returns a sorted list, Windows + // sorts environment variables upper case + LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings()); + LPTSTR p = env; + + while (size_t l = _tcslen(p)) + { + environment->push_back(reinterpret_cast<const sal_Unicode*>(p)); + p += l + 1; + } + FreeEnvironmentStrings(env); + } + + //################################################# + /* the environment list must be sorted, new values + should either replace existing ones or should be + added to the list, environment variables will + be handled case-insensitive */ + bool create_merged_environment( + rtl_uString* env_vars[], + sal_uInt32 env_vars_count, + /*in|out*/ string_container_t* merged_env) + { + OSL_ASSERT(env_vars && env_vars_count > 0 && merged_env); + + read_environment(merged_env); + + for (sal_uInt32 i = 0; i < env_vars_count; i++) + { + rtl::OUString env_var = rtl::OUString(env_vars[i]); + + if (env_var.getLength() == 0) + return false; + + iterator_pair_t iter_pair = std::equal_range( + merged_env->begin(), + merged_env->end(), + env_var, + less_environment_variable()); + + if (env_var.indexOf(NAME_VALUE_SEPARATOR) == -1) + { + merged_env->erase(iter_pair.first, iter_pair.second); + } + else + { + if (iter_pair.first != iter_pair.second) // found + *iter_pair.first = env_var; + else // not found + merged_env->insert(iter_pair.first, env_var); + } + } + return true; + } + + //################################################# + /* Create a merged environment */ + bool setup_process_environment( + rtl_uString* environment_vars[], + sal_uInt32 n_environment_vars, + /*in|out*/ environment_container_t& environment) + { + string_container_t merged_env; + if (!create_merged_environment(environment_vars, n_environment_vars, &merged_env)) + return false; + + // allocate enough space for the '\0'-separated environment strings and + // a final '\0' + environment.resize(calc_sum_of_string_lengths(merged_env) + 1); + + string_container_const_iterator_t iter = merged_env.begin(); + string_container_const_iterator_t iter_end = merged_env.end(); + + sal_uInt32 pos = 0; + for (/**/; iter != iter_end; ++iter) + { + rtl::OUString envv = *iter; + + OSL_ASSERT(envv.getLength()); + + sal_uInt32 n = envv.getLength() + 1; // copy the final '\0', too + rtl_copyMemory( + reinterpret_cast<void*>(&environment[pos]), + reinterpret_cast<const void*>(envv.getStr()), + n * sizeof(sal_Unicode)); + pos += n; + } + environment[pos] = 0; // append a final '\0' + + return true; + } + + //########################################################## + /* In contrast to the Win32 API function CreatePipe with + this function the caller is able to determine separately + which handle of the pipe is inheritable. */ + bool create_pipe( + PHANDLE p_read_pipe, + bool b_read_pipe_inheritable, + PHANDLE p_write_pipe, + bool b_write_pipe_inheritable, + LPVOID p_security_descriptor = NULL, + DWORD pipe_size = 0) + { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = p_security_descriptor; + sa.bInheritHandle = b_read_pipe_inheritable || b_write_pipe_inheritable; + + BOOL bRet = FALSE; + HANDLE hTemp = NULL; + + if (!b_read_pipe_inheritable && b_write_pipe_inheritable) + { + bRet = CreatePipe(&hTemp, p_write_pipe, &sa, pipe_size); + + if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp, + GetCurrentProcess(), p_read_pipe, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) + { + CloseHandle(hTemp); + CloseHandle(*p_read_pipe); + return false; + } + } + else if (b_read_pipe_inheritable && !b_write_pipe_inheritable) + { + bRet = CreatePipe(p_read_pipe, &hTemp, &sa, pipe_size); + + if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp, + GetCurrentProcess(), p_write_pipe, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) + { + CloseHandle(hTemp); + CloseHandle(*p_write_pipe); + return false; + } + } + else + { + bRet = CreatePipe(p_read_pipe, p_write_pipe, &sa, pipe_size); + } + return bRet; + } + + //######################################################### + // Add a quote sign to the start and the end of a string + // if not already present + rtl::OUString quote_string(const rtl::OUString& string) + { + rtl::OUStringBuffer quoted; + if (string.indexOf(QUOTE) != 0) + quoted.append(QUOTE); + + quoted.append(string); + + if (string.lastIndexOf(QUOTE) != (string.getLength() - 1)) + quoted.append(QUOTE); + + return quoted.makeStringAndClear(); + } + + //########################################################## + // Returns the system path of the executable which can either + // be provided via the strImageName parameter or as first + // element of the strArguments list. + // The returned path will be quoted if it contains spaces. + rtl::OUString get_executable_path( + rtl_uString* image_name, + rtl_uString* cmdline_args[], + sal_uInt32 n_cmdline_args, + bool search_path) + { + rtl::OUString exe_name; + + if (image_name) + exe_name = image_name; + else if (n_cmdline_args) + exe_name = rtl::OUString(cmdline_args[0]); + + rtl::OUString exe_url = exe_name; + if (search_path) + osl_searchFileURL(exe_name.pData, NULL, &exe_url.pData); + + rtl::OUString exe_path; + if (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(exe_url, exe_path)) + return rtl::OUString(); + + if (exe_path.indexOf(' ') != -1) + exe_path = quote_string(exe_path); + + return exe_path; + } + + //########################################################## + rtl::OUString get_file_extension(const rtl::OUString& file_name) + { + sal_Int32 index = file_name.lastIndexOf('.'); + if ((index != -1) && ((index + 1) < file_name.getLength())) + return file_name.copy(index + 1); + + return rtl::OUString(); + } + + //########################################################## + bool is_batch_file(const rtl::OUString& file_name) + { + rtl::OUString ext = get_file_extension(file_name); + return (ext.equalsIgnoreAsciiCaseAscii("bat") || + ext.equalsIgnoreAsciiCaseAscii("cmd") || + ext.equalsIgnoreAsciiCaseAscii("btm")); + } + + //########################################################## + rtl::OUString get_batch_processor() + { + rtl::OUString comspec; + osl_getEnvironment(ENV_COMSPEC.pData, &comspec.pData); + + OSL_ASSERT(comspec.getLength()); + + /* check if comspec path contains blanks and quote it if any */ + if (comspec.indexOf(' ') != -1) + comspec = quote_string(comspec); + + return comspec; + } + +} // namespace private + + +//################################################# +oslProcessError SAL_CALL osl_executeProcess( + rtl_uString *strImageName, + rtl_uString *strArguments[], + sal_uInt32 nArguments, + oslProcessOption Options, + oslSecurity Security, + rtl_uString *strDirectory, + rtl_uString *strEnvironmentVars[], + sal_uInt32 nEnvironmentVars, + oslProcess *pProcess +) +{ + return osl_executeProcess_WithRedirectedIO( + strImageName, + strArguments, + nArguments, + Options, + Security, + strDirectory, + strEnvironmentVars, + nEnvironmentVars, + pProcess, + NULL, NULL, NULL ); +} + +//################################################# +oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO( + rtl_uString *ustrImageName, + rtl_uString *ustrArguments[], + sal_uInt32 nArguments, + oslProcessOption Options, + oslSecurity Security, + rtl_uString *ustrDirectory, + rtl_uString *ustrEnvironmentVars[], + sal_uInt32 nEnvironmentVars, + oslProcess *pProcess, + oslFileHandle *pProcessInputWrite, + oslFileHandle *pProcessOutputRead, + oslFileHandle *pProcessErrorRead) +{ + rtl::OUString exe_path = get_executable_path( + ustrImageName, ustrArguments, nArguments, (Options & osl_Process_SEARCHPATH)); + + if (0 == exe_path.getLength()) + return osl_Process_E_NotFound; + + if (pProcess == NULL) + return osl_Process_E_InvalidError; + + DWORD flags = NORMAL_PRIORITY_CLASS; + rtl::OUStringBuffer command_line; + + if (is_batch_file(exe_path)) + { + rtl::OUString batch_processor = get_batch_processor(); + + if (batch_processor.getLength()) + { + /* cmd.exe does not work without a console window */ + if (!(Options & osl_Process_WAIT) || (Options & osl_Process_DETACHED)) + flags |= CREATE_NEW_CONSOLE; + + command_line.append(batch_processor); + command_line.appendAscii(" /c "); + } + else + // should we return here in case of error? + return osl_Process_E_Unknown; + } + + command_line.append(exe_path); + + /* Add remaining arguments to command line. If ustrImageName is NULL + the first parameter is the name of the executable so we have to + start at 1 instead of 0 */ + for (sal_uInt32 n = (NULL != ustrImageName) ? 0 : 1; n < nArguments; n++) + { + command_line.appendAscii(SPACE); + + /* Quote arguments containing blanks */ + if (rtl::OUString(ustrArguments[n]).indexOf(' ') != -1) + command_line.append(quote_string(ustrArguments[n])); + else + command_line.append(ustrArguments[n]); + } + + environment_container_t environment; + LPVOID p_environment = NULL; + + if (nEnvironmentVars && ustrEnvironmentVars) + { + if (!setup_process_environment( + ustrEnvironmentVars, nEnvironmentVars, environment)) + return osl_Process_E_InvalidError; + + flags |= CREATE_UNICODE_ENVIRONMENT; + p_environment = &environment[0]; + } + + rtl::OUString cwd; + if (ustrDirectory && ustrDirectory->length && (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(ustrDirectory, cwd))) + return osl_Process_E_InvalidError; + + LPCWSTR p_cwd = (cwd.getLength()) ? reinterpret_cast<LPCWSTR>(cwd.getStr()) : NULL; + + if ((Options & osl_Process_DETACHED) && !(flags & CREATE_NEW_CONSOLE)) + flags |= DETACHED_PROCESS; + + STARTUPINFO startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + + startup_info.cb = sizeof(STARTUPINFO); + startup_info.dwFlags = STARTF_USESHOWWINDOW; + startup_info.lpDesktop = L""; + + /* Create pipes for redirected IO */ + HANDLE hInputRead = NULL; + HANDLE hInputWrite = NULL; + if (pProcessInputWrite && create_pipe(&hInputRead, true, &hInputWrite, false)) + startup_info.hStdInput = hInputRead; + + HANDLE hOutputRead = NULL; + HANDLE hOutputWrite = NULL; + if (pProcessOutputRead && create_pipe(&hOutputRead, false, &hOutputWrite, true)) + startup_info.hStdOutput = hOutputWrite; + + HANDLE hErrorRead = NULL; + HANDLE hErrorWrite = NULL; + if (pProcessErrorRead && create_pipe(&hErrorRead, false, &hErrorWrite, true)) + startup_info.hStdError = hErrorWrite; + + bool b_inherit_handles = false; + if (pProcessInputWrite || pProcessOutputRead || pProcessErrorRead) + { + startup_info.dwFlags |= STARTF_USESTDHANDLES; + b_inherit_handles = true; + } + + switch(Options & (osl_Process_NORMAL | osl_Process_HIDDEN | osl_Process_MINIMIZED | osl_Process_MAXIMIZED | osl_Process_FULLSCREEN)) + { + case osl_Process_HIDDEN: + startup_info.wShowWindow = SW_HIDE; + flags |= CREATE_NO_WINDOW; // ignored for non-console + // applications; ignored on + // Win9x + break; + + case osl_Process_MINIMIZED: + startup_info.wShowWindow = SW_MINIMIZE; + break; + + case osl_Process_MAXIMIZED: + case osl_Process_FULLSCREEN: + startup_info.wShowWindow = SW_MAXIMIZE; + break; + + default: + startup_info.wShowWindow = SW_NORMAL; + } + + rtl::OUString cmdline = command_line.makeStringAndClear(); + PROCESS_INFORMATION process_info; + BOOL bRet = FALSE; + + if ((Security != NULL) && (((oslSecurityImpl*)Security)->m_hToken != NULL)) + { + bRet = CreateProcessAsUser( + ((oslSecurityImpl*)Security)->m_hToken, + NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL, + b_inherit_handles, flags, p_environment, p_cwd, + &startup_info, &process_info); + } + else + { + bRet = CreateProcess( + NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL, + b_inherit_handles, flags, p_environment, p_cwd, + &startup_info, &process_info); + } + + /* Now we can close the pipe ends that are used by the child process */ + + if (hInputRead) + CloseHandle(hInputRead); + + if (hOutputWrite) + CloseHandle(hOutputWrite); + + if (hErrorWrite) + CloseHandle(hErrorWrite); + + if (bRet) + { + CloseHandle(process_info.hThread); + + oslProcessImpl* pProcImpl = reinterpret_cast<oslProcessImpl*>( + rtl_allocateMemory(sizeof(oslProcessImpl))); + + if (pProcImpl != NULL) + { + pProcImpl->m_hProcess = process_info.hProcess; + pProcImpl->m_IdProcess = process_info.dwProcessId; + + *pProcess = (oslProcess)pProcImpl; + + if (Options & osl_Process_WAIT) + WaitForSingleObject(pProcImpl->m_hProcess, INFINITE); + + if (pProcessInputWrite) + *pProcessInputWrite = osl_createFileHandleFromOSHandle(hInputWrite, osl_File_OpenFlag_Write); + + if (pProcessOutputRead) + *pProcessOutputRead = osl_createFileHandleFromOSHandle(hOutputRead, osl_File_OpenFlag_Read); + + if (pProcessErrorRead) + *pProcessErrorRead = osl_createFileHandleFromOSHandle(hErrorRead, osl_File_OpenFlag_Read); + + return osl_Process_E_None; + } + } + + /* if an error occured we have to close the server side pipe ends too */ + + if (hInputWrite) + CloseHandle(hInputWrite); + + if (hOutputRead) + CloseHandle(hOutputRead); + + if (hErrorRead) + CloseHandle(hErrorRead); + + return osl_Process_E_Unknown; +} diff --git a/sal/osl/w32/procimpl.h b/sal/osl/w32/procimpl.h new file mode 100644 index 000000000000..b783f9b52ae2 --- /dev/null +++ b/sal/osl/w32/procimpl.h @@ -0,0 +1,47 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_PROCIMPL_H_ +#define _OSL_PROCIMPL_H_ + +#include <osl/process.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _oslProcessImpl { + HANDLE m_hProcess; + DWORD m_IdProcess; +} oslProcessImpl; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/w32/profile.cxx b/sal/osl/w32/profile.cxx new file mode 100644 index 000000000000..9f4ea5630e1f --- /dev/null +++ b/sal/osl/w32/profile.cxx @@ -0,0 +1,2707 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2010 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "system.h" + +#include "file_url.h" +#include "path_helper.hxx" + +#include <osl/diagnose.h> +#include <osl/profile.h> +#include <osl/process.h> +#include <osl/file.h> +#include <osl/util.h> +#include <rtl/alloc.h> +#include <algorithm> +using std::min; +static inline void copy_ustr_n( void *dest, const void *source, size_t length ) { rtl_copyMemory(dest, source, length*sizeof(sal_Unicode)); } + +#define LINES_INI 32 +#define LINES_ADD 10 +#define SECTIONS_INI 5 +#define SECTIONS_ADD 3 +#define ENTRIES_INI 5 +#define ENTRIES_ADD 3 + + +#define STR_INI_EXTENSION L".ini" +#define STR_INI_METAHOME "?~" +#define STR_INI_METASYS "?$" +#define STR_INI_METACFG "?^" +#define STR_INI_METAINS "?#" + +#define STR_INI_BOOLYES "yes" +#define STR_INI_BOOLON "on" +#define STR_INI_BOOLONE "1" +#define STR_INI_BOOLNO "no" +#define STR_INI_BOOLOFF "off" +#define STR_INI_BOOLZERO "0" + +#define FLG_USER 0x00FF +#define FLG_AUTOOPEN 0x0100 +#define FLG_MODIFIED 0x0200 + +#define SVERSION_LOCATION STR_INI_METACFG +#define SVERSION_FALLBACK STR_INI_METASYS +#define SVERSION_NAME "sversion" +#define SVERSION_SECTION "Versions" +#define SVERSION_SOFFICE "StarOffice" +#define SVERSION_PROFILE "soffice.ini" +#define SVERSION_OPTION "userid:" +#define SVERSION_DIRS { "bin", "program" } +#define SVERSION_USER "user" + +#define DEFAULT_PMODE (_S_IREAD | _S_IWRITE) + +#define _BUILD_STR_(n) # n +#define BUILD_STR(n) _BUILD_STR_(n) + + +/*#define DEBUG_OSL_PROFILE 1*/ +/*#define TRACE_OSL_PROFILE 1*/ + + +/*****************************************************************************/ +/* Data Type Definition */ +/*****************************************************************************/ + +typedef FILETIME osl_TStamp; + +typedef enum _osl_TLockMode +{ + un_lock, read_lock, write_lock +} osl_TLockMode; + +typedef struct _osl_TFile +{ + HANDLE m_Handle; + sal_Char* m_pReadPtr; + sal_Char m_ReadBuf[512]; +/* sal_Char* m_pWritePtr; */ +/* sal_Char m_WriteBuf[512]; */ + sal_Char* m_pWriteBuf; + sal_uInt32 m_nWriteBufLen; + sal_uInt32 m_nWriteBufFree; +} osl_TFile; + +typedef struct _osl_TProfileEntry +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; +} osl_TProfileEntry; + +typedef struct _osl_TProfileSection +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; + sal_uInt32 m_NoEntries; + sal_uInt32 m_MaxEntries; + osl_TProfileEntry* m_Entries; +} osl_TProfileSection; + + +/* + Profile-data structure hidden behind oslProfile: +*/ +typedef struct _osl_TProfileImpl +{ + sal_uInt32 m_Flags; + osl_TFile* m_pFile; + osl_TStamp m_Stamp; + sal_uInt32 m_NoLines; + sal_uInt32 m_MaxLines; + sal_uInt32 m_NoSections; + sal_uInt32 m_MaxSections; + sal_Char** m_Lines; + rtl_uString *m_strFileName; + osl_TProfileSection* m_Sections; +} osl_TProfileImpl; + + +/*****************************************************************************/ +/* Static Module Function Declarations */ +/*****************************************************************************/ + +static osl_TFile* openFileImpl(rtl_uString * strFileName, oslProfileOption ProfileFlags ); +static osl_TStamp closeFileImpl(osl_TFile* pFile); +static sal_Bool lockFile(const osl_TFile* pFile, osl_TLockMode eMode); +static sal_Bool rewindFile(osl_TFile* pFile, sal_Bool bTruncate); +static osl_TStamp getFileStamp(osl_TFile* pFile); + +static sal_Bool getLine(osl_TFile* pFile, const sal_Char *pszLine, int MaxLen); +static sal_Bool putLine(osl_TFile* pFile, const sal_Char *pszLine); +static const sal_Char* stripBlanks(const sal_Char* String, sal_uInt32* pLen); +static const sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line); +static const sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo); +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo); +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + const sal_Char* Entry, sal_uInt32 Len); +static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, const sal_Char* Entry, sal_uInt32 Len); +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry); +static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len); +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection); +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section, + const sal_Char* Entry, sal_uInt32 *pNoEntry); +static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile); +static sal_Bool storeProfile(osl_TProfileImpl* pProfile, sal_Bool bCleanup); +static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable); +static sal_Bool releaseProfile(osl_TProfileImpl* pProfile); +static sal_Bool lookupProfile(const sal_Unicode *strPath, const sal_Unicode *strFile, sal_Unicode *strProfile); + +static sal_Bool writeProfileImpl (osl_TFile* pFile); +static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl*); +static sal_Bool osl_ProfileSwapProfileNames(osl_TProfileImpl*); +static rtl_uString* osl_ProfileGenerateExtension(rtl_uString* ustrFileName, rtl_uString* ustrExtension); + +static sal_Bool SAL_CALL osl_getProfileName(rtl_uString* strPath, rtl_uString* strName, rtl_uString** strProfileName); + +/*****************************************************************************/ +/* Exported Module Functions */ +/*****************************************************************************/ + +oslProfile SAL_CALL osl_openProfile(rtl_uString *strProfileName, sal_uInt32 Flags) +{ + osl_TFile* pFile = NULL; + osl_TProfileImpl* pProfile; + rtl_uString *FileName=NULL; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_openProfile\n"); +#endif + OSL_VERIFY(strProfileName); + + if (rtl_uString_getLength(strProfileName) == 0 ) + { + OSL_VERIFY(osl_getProfileName(NULL, NULL, &FileName)); + } + else + { + rtl_uString_assign(&FileName, strProfileName); + } + + + osl_getSystemPathFromFileURL(FileName, &FileName); + + +#ifdef DEBUG_OSL_PROFILE + Flags=osl_Profile_FLUSHWRITE; + + // OSL_TRACE("opening '%s'\n",FileName); + if ( Flags == osl_Profile_DEFAULT ) + { + OSL_TRACE("with osl_Profile_DEFAULT \n"); + } + if ( Flags & osl_Profile_SYSTEM ) + { + OSL_TRACE("with osl_Profile_SYSTEM \n"); + } + if ( Flags & osl_Profile_READLOCK ) + { + OSL_TRACE("with osl_Profile_READLOCK \n"); + } + if ( Flags & osl_Profile_WRITELOCK ) + { + OSL_TRACE("with osl_Profile_WRITELOCK \n"); + } +/* if ( Flags & osl_Profile_READWRITE ) */ +/* { */ +/* OSL_TRACE("with osl_Profile_READWRITE \n"); */ +/* } */ + if ( Flags & osl_Profile_FLUSHWRITE ) + { + OSL_TRACE("with osl_Profile_FLUSHWRITE \n"); + } +#endif + + if ( (! (Flags & osl_Profile_SYSTEM)) && ( (pFile = openFileImpl(FileName, Flags) ) == NULL ) ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_openProfile [not opened]\n"); +#endif + if( FileName) + rtl_uString_release( FileName); + + return (NULL); + } + + + pProfile = (osl_TProfileImpl*)calloc(1, sizeof(osl_TProfileImpl)); + + + pProfile->m_Flags = Flags & FLG_USER; + osl_getSystemPathFromFileURL(strProfileName, &pProfile->m_strFileName); +// rtl_uString_assign(&pProfile->m_strFileName, strProfileName); + + if (Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE )) + pProfile->m_pFile = pFile; + + pProfile->m_Stamp = getFileStamp(pFile); + + loadProfile(pFile, pProfile); + + if (pProfile->m_pFile == NULL) + closeFileImpl(pFile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_openProfile [ok]\n"); +#endif + if( FileName) + rtl_uString_release( FileName); + + return (pProfile); +} + +sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_closeProfile\n"); +#endif + + if ( Profile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [profile==0]\n"); +#endif + return sal_False; + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + pProfile = acquireProfile(Profile,sal_True); + + if ( pProfile != 0 ) + { + if ( !( pProfile->m_Flags & osl_Profile_READLOCK ) && ( pProfile->m_Flags & FLG_MODIFIED ) ) + { +/* if (pProfile->m_pFile == NULL) */ +/* pProfile->m_pFile = openFileImpl(pProfile->m_Filename, sal_True); */ + + storeProfile(pProfile, sal_False); + } + } + else + { + pProfile = acquireProfile(Profile,sal_False); + } + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [pProfile==0]\n"); +#endif + return sal_False; + } + + if (pProfile->m_pFile != NULL) + closeFileImpl(pProfile->m_pFile); + } + + pProfile->m_pFile = NULL; + rtl_uString_release(pProfile->m_strFileName); + pProfile->m_strFileName = NULL; + + /* release whole profile data types memory */ + if ( pProfile->m_NoLines > 0) + { + unsigned int index=0; + if ( pProfile->m_Lines != 0 ) + { + for ( index = 0 ; index < pProfile->m_NoLines ; ++index) + { + if ( pProfile->m_Lines[index] != 0 ) + { + free(pProfile->m_Lines[index]); + } + } + free(pProfile->m_Lines); + } + if ( pProfile->m_Sections != 0 ) + { + /*osl_TProfileSection* pSections=pProfile->m_Sections;*/ + for ( index = 0 ; index < pProfile->m_NoSections ; ++index ) + { + if ( pProfile->m_Sections[index].m_Entries != 0 ) + { + free(pProfile->m_Sections[index].m_Entries); + } + } + free(pProfile->m_Sections); + } + + } + free(pProfile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [ok]\n"); +#endif + return (sal_True); +} + + +sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*) Profile; + osl_TFile* pFile; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_flushProfile()\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [pProfile == 0]\n"); +#endif + return sal_False; + } + + pFile = pProfile->m_pFile; + if ( !( pFile != 0 && pFile->m_Handle >= 0 ) ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [invalid file]\n"); +#endif + return sal_False; + } + + if ( pProfile->m_Flags & FLG_MODIFIED ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("swapping to storeprofile\n"); +#endif + bRet = storeProfile(pProfile,sal_False); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [ok]\n"); +#endif + return bRet; +} + +static sal_Bool writeProfileImpl(osl_TFile* pFile) +{ + DWORD BytesWritten=0; + BOOL bRet; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileImpl()\n"); +#endif + + if ( !( pFile != 0 && pFile->m_Handle != INVALID_HANDLE_VALUE ) || ( pFile->m_pWriteBuf == 0 ) ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileImpl() [invalid args]\n"); +#endif + return sal_False; + } + +#ifdef DEBUG_OSL_PROFILE +/* OSL_TRACE("File Buffer in writeProfileImpl '%s' size == '%i' '%i'(%i)\n", + pFile->m_pWriteBuf,pFile->m_nWriteBufLen,strlen(pFile->m_pWriteBuf),pFile->m_nWriteBufLen - pFile->m_nWriteBufFree);*/ +#endif + + bRet=WriteFile(pFile->m_Handle, pFile->m_pWriteBuf, pFile->m_nWriteBufLen - pFile->m_nWriteBufFree,&BytesWritten,NULL); + + if ( bRet == 0 || BytesWritten <= 0 ) + { + OSL_ENSURE(bRet,"WriteFile failed!!!"); + + OSL_TRACE("write failed '%s'\n",strerror(errno)); + +/* OSL_TRACE("Out osl_writeProfileImpl() [write '%s']\n",strerror(errno));*/ + return (sal_False); + } + + free(pFile->m_pWriteBuf); + pFile->m_pWriteBuf=0; + pFile->m_nWriteBufLen=0; + pFile->m_nWriteBufFree=0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileImpl() [ok]\n"); +#endif + return sal_True; +} + + +sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Char* pszString, sal_uInt32 MaxLen, + const sal_Char* pszDefault) +{ + sal_uInt32 NoEntry; + const sal_Char* pStr = 0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileString\n"); +#endif + + pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pProfile==0]\n"); +#endif + + + return (sal_False); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) && + (NoEntry < pSec->m_NoEntries) && + ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line], + '=')) != NULL)) + pStr++; + else + pStr = pszDefault; + + if ( pStr != 0 ) + { + pStr = stripBlanks(pStr, NULL); + MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr); + pStr = stripBlanks(pStr, &MaxLen); + strncpy(pszString, pStr, MaxLen); + pszString[MaxLen] = '\0'; + } + } + else + { + ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH ); + + WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL); + GetPrivateProfileString(pszSection, pszEntry, pszDefault, pszString, MaxLen, aFileName); + } + + releaseProfile(pProfile); + + if ( pStr == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pStr==0]\n"); +#endif + + + return (sal_False); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [ok]\n"); +#endif + + + + + return (sal_True); +} + + +sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Bool Default) +{ + sal_Char Line[32]; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileBool\n"); +#endif + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + if ((stricmp(Line, STR_INI_BOOLYES) == 0) || + (stricmp(Line, STR_INI_BOOLON) == 0) || + (stricmp(Line, STR_INI_BOOLONE) == 0)) + Default = sal_True; + else + if ((stricmp(Line, STR_INI_BOOLNO) == 0) || + (stricmp(Line, STR_INI_BOOLOFF) == 0) || + (stricmp(Line, STR_INI_BOOLZERO) == 0)) + Default = sal_False; + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileBool [ok]\n"); +#endif + + return (Default); +} + + +sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_uInt32 FirstId, const sal_Char* Strings[], + sal_uInt32 Default) +{ + sal_uInt32 i; + sal_Char Line[256]; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileIdent\n"); +#endif + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + i = 0; + while (Strings[i] != NULL) + { + if (stricmp(Line, Strings[i]) == 0) + { + Default = i + FirstId; + break; + } + i++; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileIdent [ok]\n"); +#endif + return (Default); +} + +sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + const sal_Char* pszString) +{ + sal_uInt32 i; + sal_Bool bRet = sal_False; + sal_uInt32 NoEntry; + const sal_Char* pStr; + sal_Char Line[4096]; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileString\n"); +#endif + + pProfile = acquireProfile(Profile, sal_True); + + if (pProfile == NULL) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [pProfile==0]\n"); +#endif + return (sal_False); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == NULL) + { + Line[0] = '\0'; + addLine(pProfile, Line); + + Line[0] = '['; + strcpy(&Line[1], pszSection); + Line[1 + strlen(pszSection)] = ']'; + Line[2 + strlen(pszSection)] = '\0'; + + if (((pStr = addLine(pProfile, Line)) == NULL) || + (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection)))) + { + releaseProfile(pProfile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not added]\n"); +#endif + return (sal_False); + } + + pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1]; + NoEntry = pSec->m_NoEntries; + } + + Line[0] = '\0'; + strcpy(&Line[0], pszEntry); + Line[0 + strlen(pszEntry)] = '='; + strcpy(&Line[1 + strlen(pszEntry)], pszString); + + if (NoEntry >= pSec->m_NoEntries) + { + if (pSec->m_NoEntries > 0) + i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1; + else + i = pSec->m_Line + 1; + + if (((pStr = insertLine(pProfile, Line, i)) == NULL) || + (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry)))) + { + releaseProfile(pProfile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not inserted]\n"); +#endif + return (sal_False); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + else + { + i = pSec->m_Entries[NoEntry].m_Line; + free(pProfile->m_Lines[i]); + pProfile->m_Lines[i] = strdup(Line); + setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry)); + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else + { + ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH ); + + WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL); + WritePrivateProfileString(pszSection, pszEntry, pszString, aFileName); + } + + bRet = releaseProfile(pProfile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [ok]\n"); +#endif + return bRet; +} + + +sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Bool Value) +{ + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileBool\n"); +#endif + + if (Value) + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE); + else + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileBool [ok]\n"); +#endif + + return bRet; +} + + +sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_uInt32 FirstId, const sal_Char* Strings[], + sal_uInt32 Value) +{ + int i, n; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileIdent\n"); +#endif + + for (n = 0; Strings[n] != NULL; n++); + + if ((i = Value - FirstId) >= n) + bRet=sal_False; + else + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileIdent\n"); +#endif + return bRet; +} + + +sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile, + const sal_Char *pszSection, const sal_Char *pszEntry) +{ + sal_uInt32 NoEntry; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_removeProfileEntry\n"); +#endif + + pProfile = acquireProfile(Profile, sal_True); + + if (pProfile == NULL) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [pProfile==0]\n"); +#endif + + + return (sal_False); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) && + (NoEntry < pSec->m_NoEntries)) + { + removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line); + removeEntry(pSec, NoEntry); + if (pSec->m_NoEntries == 0) + { + removeLine(pProfile, pSec->m_Line); + + /* remove any empty separation line */ + if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0')) + removeLine(pProfile, pSec->m_Line - 1); + + removeSection(pProfile, pSec); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else + { + ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH ); + + WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL); + WritePrivateProfileString(pszSection, pszEntry, NULL, aFileName); + } + + bRet = releaseProfile(pProfile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [ok]\n"); +#endif + return bRet; +} + + +sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile, const sal_Char *pszSection, + sal_Char* pszBuffer, sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + sal_uInt32 NoEntry; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_getProfileSectionEntries\n"); +#endif + + pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [pProfile=0]\n"); +#endif + + + return (0); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != NULL) + { + if (MaxLen != 0) + { + for (i = 0; i < pSec->m_NoEntries; i++) + { + if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len); + n += pSec->m_Entries[i].m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pSec->m_NoEntries; i++) + n += pSec->m_Entries[i].m_Len + 1; + + n += 1; + } + } + else + n = 0; + } + else + { + ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH ); + + WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL); + n = GetPrivateProfileString(pszSection, NULL, NULL, pszBuffer, MaxLen, aFileName); + } + + releaseProfile(pProfile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [ok]\n"); +#endif + + return (n); +} + + +sal_Bool SAL_CALL osl_getProfileName(rtl_uString* strPath, rtl_uString* strName, rtl_uString** strProfileName) +{ + sal_Bool bFailed; + ::osl::LongPathBuffer< sal_Unicode > aFile( MAX_LONG_PATH ); + ::osl::LongPathBuffer< sal_Unicode > aPath( MAX_LONG_PATH ); + sal_uInt32 nFileLen = 0; + sal_uInt32 nPathLen = 0; + + rtl_uString * strTmp = NULL; + oslFileError nError; + + /* build file name */ + if (strName && strName->length) + { + if( ::sal::static_int_cast< sal_uInt32 >( strName->length ) >= aFile.getBufSizeInSymbols() ) + return sal_False; + + copy_ustr_n( aFile, strName->buffer, strName->length+1); + nFileLen = strName->length; + + if (rtl_ustr_indexOfChar( aFile, L'.' ) == -1) + { + if (nFileLen + wcslen(STR_INI_EXTENSION) >= aFile.getBufSizeInSymbols()) + return sal_False; + + /* add default extension */ + copy_ustr_n( aFile + nFileLen, STR_INI_EXTENSION, wcslen(STR_INI_EXTENSION)+1 ); + nFileLen += wcslen(STR_INI_EXTENSION); + } + } + else + { + rtl_uString *strProgName = NULL; + sal_Unicode *pProgName; + sal_Int32 nOffset = 0; + sal_Int32 nLen; + sal_Int32 nPos; + + if (osl_getExecutableFile(&strProgName) != osl_Process_E_None) + return sal_False; + + /* remove path and extension from filename */ + pProgName = strProgName->buffer; + nLen = strProgName->length ; + + if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L'/' )) != -1) + nOffset = nPos + 1; + else if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L':' )) != -1) + nOffset = nPos + 1; + + if ((nPos = rtl_ustr_lastIndexOfChar( pProgName, L'.' )) != -1 ) + nLen -= 4; + + if ((nFileLen = nLen - nOffset) >= aFile.getBufSizeInSymbols()) + return sal_False; + + copy_ustr_n(aFile, pProgName + nOffset, nFileLen); + + if (nFileLen + wcslen(STR_INI_EXTENSION) >= aFile.getBufSizeInSymbols()) + return sal_False; + + /* add default extension */ + copy_ustr_n(aFile + nFileLen, STR_INI_EXTENSION, wcslen(STR_INI_EXTENSION)+1); + nFileLen += wcslen(STR_INI_EXTENSION); + + rtl_uString_release( strProgName ); + } + + if (aFile[0] == 0) + return sal_False; + + /* build directory path */ + if (strPath && strPath->length) + { + sal_Unicode *pPath = rtl_uString_getStr(strPath); + sal_Int32 nLen = rtl_uString_getLength(strPath); + + if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METAHOME) , STR_INI_METAHOME) == 0) && + ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)] == '/'))) + { + rtl_uString * strHome = NULL; + oslSecurity security = osl_getCurrentSecurity(); + + bFailed = ! osl_getHomeDir(security, &strHome); + osl_freeSecurityHandle(security); + + if (bFailed) return (sal_False); + + if ( ::sal::static_int_cast< sal_uInt32 >( strHome->length ) >= aPath.getBufSizeInSymbols()) + return sal_False; + + copy_ustr_n( aPath, strHome->buffer, strHome->length+1); + nPathLen = strHome->length; + + if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METAHOME)) + { + pPath += RTL_CONSTASCII_LENGTH(STR_INI_METAHOME); + nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METAHOME); + + if (nLen + nPathLen >= aPath.getBufSizeInSymbols()) + return sal_False; + + copy_ustr_n(aPath + nPathLen, pPath, nLen+1); + nPathLen += nLen; + } + + rtl_uString_release(strHome); + } + + else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METACFG), STR_INI_METACFG) == 0) && + ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METACFG)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METACFG)] == '/'))) + { + rtl_uString * strConfig = NULL; + oslSecurity security = osl_getCurrentSecurity(); + + bFailed = ! osl_getConfigDir(security, &strConfig); + osl_freeSecurityHandle(security); + + if (bFailed) return (sal_False); + + if ( ::sal::static_int_cast< sal_uInt32 >( strConfig->length ) >= aPath.getBufSizeInSymbols()) + return sal_False; + + copy_ustr_n( aPath, strConfig->buffer, strConfig->length+1 ); + nPathLen = strConfig->length; + + if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METACFG)) + { + pPath += RTL_CONSTASCII_LENGTH(STR_INI_METACFG); + nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METACFG); + + if (nLen + nPathLen >= aPath.getBufSizeInSymbols()) + return sal_False; + + copy_ustr_n(aPath + nPathLen, pPath, nLen+1); + nPathLen += nLen; + } + + rtl_uString_release(strConfig); + } + + else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METASYS), STR_INI_METASYS) == 0) && + ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METASYS)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METASYS)] == '/'))) + { + if (((nPathLen = GetWindowsDirectoryW(::osl::mingw_reinterpret_cast<LPWSTR>(aPath), aPath.getBufSizeInSymbols())) == 0) || (nPathLen >= aPath.getBufSizeInSymbols())) + return (sal_False); + + if (nLen > RTL_CONSTASCII_LENGTH(STR_INI_METASYS)) + { + pPath += RTL_CONSTASCII_LENGTH(STR_INI_METASYS); + nLen -= RTL_CONSTASCII_LENGTH(STR_INI_METASYS); + + if (nLen + nPathLen >= aPath.getBufSizeInSymbols()) + return sal_False; + + copy_ustr_n(aPath + nPathLen, pPath, nLen+1); + nPathLen += nLen; + } + } + + else if ((rtl_ustr_ascii_compare_WithLength(pPath, RTL_CONSTASCII_LENGTH(STR_INI_METAINS), STR_INI_METAINS) == 0) && + ((nLen == RTL_CONSTASCII_LENGTH(STR_INI_METAINS)) || (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAINS)] == '/') || + (pPath[RTL_CONSTASCII_LENGTH(STR_INI_METAINS)] == '"') ) ) + { + if (! lookupProfile(pPath + RTL_CONSTASCII_LENGTH(STR_INI_METAINS), aFile, aPath)) + return (sal_False); + + nPathLen = rtl_ustr_getLength(aPath); + } + + else if( ::sal::static_int_cast< sal_uInt32 >( nLen ) < aPath.getBufSizeInSymbols()) + { + copy_ustr_n(aPath, pPath, nLen+1); + nPathLen = rtl_ustr_getLength(aPath); + } + else + return sal_False; + } + else + { + rtl_uString * strConfigDir = NULL; + oslSecurity security = osl_getCurrentSecurity(); + + bFailed = ! osl_getConfigDir(security, &strConfigDir); + osl_freeSecurityHandle(security); + + if (bFailed) return (sal_False); + if ( ::sal::static_int_cast< sal_uInt32 >( strConfigDir->length ) >= aPath.getBufSizeInSymbols() ) + return sal_False; + + copy_ustr_n(aPath, strConfigDir->buffer, strConfigDir->length+1); + nPathLen = strConfigDir->length; + } + + if (nPathLen && (aPath[nPathLen - 1] != L'/') && (aPath[nPathLen - 1] != L'\\')) + { + aPath[nPathLen++] = L'\\'; + aPath[nPathLen] = 0; + } + + if (nPathLen + nFileLen >= aPath.getBufSizeInSymbols()) + return sal_False; + + /* append file name */ + copy_ustr_n(aPath + nPathLen, aFile, nFileLen+1); + nPathLen += nFileLen; + + /* copy filename */ + rtl_uString_newFromStr_WithLength(&strTmp, aPath, nPathLen); + nError = osl_getFileURLFromSystemPath(strTmp, strProfileName); + rtl_uString_release(strTmp); + + return (sal_Bool) (nError == osl_File_E_None); +} + + +sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile, sal_Char* pszBuffer, sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + return (0); + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (MaxLen != 0) + { + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if ((n + pSec->m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], + pSec->m_Len); + n += pSec->m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pProfile->m_NoSections; i++) + n += pProfile->m_Sections[i].m_Len + 1; + + n += 1; + } + } + else + { + ::osl::LongPathBuffer< sal_Char > aFileName( MAX_LONG_PATH ); + + WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(pProfile->m_strFileName->buffer), -1, aFileName, aFileName.getBufSizeInSymbols(), NULL, NULL); + n = GetPrivateProfileSectionNames(pszBuffer, MaxLen, aFileName); + } + + releaseProfile(pProfile); + + return (n); +} + + + + +/*****************************************************************************/ +/* Static Module Functions */ +/*****************************************************************************/ + +static osl_TStamp getFileStamp(osl_TFile* pFile) +{ + FILETIME FileTime; + + if ((pFile->m_Handle == INVALID_HANDLE_VALUE) || + (! GetFileTime(pFile->m_Handle, NULL, NULL, &FileTime))) + memset(&FileTime, 0, sizeof(FileTime)); + + return (FileTime); +} + + + +static sal_Bool lockFile(const osl_TFile* pFile, osl_TLockMode eMode) +{ + sal_Bool status = sal_False; + OVERLAPPED Overlapped; + + if (pFile->m_Handle == INVALID_HANDLE_VALUE) + return (sal_False); + + memset(&Overlapped, 0, sizeof(Overlapped)); + + switch (eMode) + { + case un_lock: + status = (sal_Bool) UnlockFileEx( + pFile->m_Handle, 0, 0xFFFFFFFF, 0, &Overlapped); + break; + + case read_lock: + status = (sal_Bool) LockFileEx( + pFile->m_Handle, 0, 0, 0xFFFFFFFF, 0, &Overlapped); + break; + + case write_lock: + status = (sal_Bool) LockFileEx( + pFile->m_Handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 0xFFFFFFFF, 0, + &Overlapped); + break; + } + + return (status); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +static osl_TFile* openFileImpl(rtl_uString * strFileName, oslProfileOption ProfileFlags ) +{ + osl_TFile* pFile = reinterpret_cast< osl_TFile*>( calloc( 1, sizeof(osl_TFile) ) ); + sal_Bool bWriteable = sal_False; + +/* if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE | osl_Profile_READWRITE ) )*/ + if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("setting bWriteable to TRUE\n"); +#endif + bWriteable=sal_True; + } + + if (! bWriteable) + { +#if 0 +//#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("opening '%s' read only\n",pszFilename); +#endif + + pFile->m_Handle = CreateFileW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strFileName )), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + /* mfe: argghh!!! do not check if the file could be openend */ + /* default mode expects it that way!!! */ + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("opening '%s' read/write\n",pszFilename); +#endif + + if ((pFile->m_Handle = CreateFileW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strFileName )), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) + == INVALID_HANDLE_VALUE) + { + free(pFile); + return (NULL); + } + } + + pFile->m_pWriteBuf=0; + pFile->m_nWriteBufFree=0; + pFile->m_nWriteBufLen=0; + + if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("locking '%s' file\n",pszFilename); +#endif + + lockFile(pFile, bWriteable ? write_lock : read_lock); + } + + /* mfe: new WriteBuf obsolete */ +/* pFile->m_pWritePtr = pFile->m_Buf;*/ +/* pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);*/ + + return (pFile); +} + + + + + + + + + +static osl_TStamp closeFileImpl(osl_TFile* pFile) +{ + osl_TStamp stamp = {0, 0}; + + if ( pFile == 0 ) + { + return stamp; + } + + if (pFile->m_Handle != INVALID_HANDLE_VALUE) + { + /* mfe: new WriteBuf obsolete */ + /* we just closing the file here, DO NOT write, it has to be handled in higher levels */ +/* if (pFile->m_pWritePtr > pFile->m_Buf)*/ +/* {*/ +/* DWORD Bytes;*/ + +/* WriteFile(pFile->m_Handle, pFile->m_WriteBuf,*/ +/* pFile->m_pWritePtr - pFile->m_WriteBuf,*/ +/* &Bytes, NULL);*/ +/* }*/ + + stamp = getFileStamp(pFile); + + lockFile(pFile, un_lock); + + CloseHandle(pFile->m_Handle); + pFile->m_Handle = INVALID_HANDLE_VALUE; + } + + if ( pFile->m_pWriteBuf != 0 ) + { + free(pFile->m_pWriteBuf); + } + + free(pFile); + + return(stamp); +} + + + + + + + + +static sal_Bool rewindFile(osl_TFile* pFile, sal_Bool bTruncate) +{ + if (pFile->m_Handle != INVALID_HANDLE_VALUE) + { + /* mfe: new WriteBuf obsolete */ + /* we just closing the file here, DO NOT write, it has to be handled in higher levels */ +/* if (pFile->m_pWritePtr > pFile->m_WriteBuf)*/ +/* {*/ +/* DWORD Bytes;*/ + +/* WriteFile(pFile->m_Handle, pFile->m_WriteBuf,*/ +/* pFile->m_pWritePtr - pFile->m_WriteBuf,*/ +/* &Bytes, NULL);*/ + +/* pFile->m_pWritePtr = pFile->m_WriteBuf;*/ +/* }*/ + + pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + + SetFilePointer(pFile->m_Handle, 0, NULL, FILE_BEGIN); + + if (bTruncate) + SetEndOfFile(pFile->m_Handle); + } + + return (sal_True); +} + + + + + + + + + + +static sal_Bool getLine(osl_TFile* pFile, const sal_Char *pszLine, int MaxLen) +{ + DWORD Max; + size_t Free, Bytes; + sal_Char* pChr; + sal_Char* pLine = (sal_Char *)pszLine; + + if (pFile->m_Handle == INVALID_HANDLE_VALUE) + return (sal_False); + + MaxLen -= 1; + + do + { + Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf); + + if (Bytes <= 1) + { + /* refill buffer */ + memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes); + pFile->m_pReadPtr = pFile->m_ReadBuf; + + Free = sizeof(pFile->m_ReadBuf) - Bytes; + + if (! ReadFile(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free, &Max, NULL)) + { + *pLine = '\0'; + return (sal_False); + } + + if (Max < Free) + { + if ((Max == 0) && (pLine == pszLine)) + { + *pLine = '\0'; + return (sal_False); + } + + pFile->m_ReadBuf[Bytes + Max] = '\0'; + } + } + + for (pChr = pFile->m_pReadPtr; + (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') && + (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)); + pChr++); + + Max = min(pChr - pFile->m_pReadPtr, MaxLen); + memcpy(pLine, pFile->m_pReadPtr, Max); + MaxLen -= Max; + pLine += Max; + + if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)) + { + if (*pChr != '\0') + { + if ((pChr[0] == '\r') && (pChr[1] == '\n')) + pChr += 2; + else + pChr += 1; + } + + if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) && + (*pChr == '\0')) + pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + + *pLine = '\0'; + + /* setting MaxLen to -1 indicates terminating read loop */ + MaxLen = -1; + } + + pFile->m_pReadPtr = pChr; + } + while (MaxLen > 0); + + return (sal_True); +} + + + + + + + + + + +static sal_Bool putLine(osl_TFile* pFile, const sal_Char *pszLine) +{ + unsigned int Len = strlen(pszLine); + +#ifdef DEBUG_OSL_PROFILE + int strLen=0; +#endif + + if ( pFile == 0 || pFile->m_Handle < 0 ) + { + return (sal_False); + } + + if ( pFile->m_pWriteBuf == 0 ) + { + pFile->m_pWriteBuf = (sal_Char*) malloc(Len+3); + pFile->m_nWriteBufLen = Len+3; + pFile->m_nWriteBufFree = Len+3; + } + else + { + if ( pFile->m_nWriteBufFree <= Len + 3 ) + { + sal_Char* pTmp; + + pTmp=(sal_Char*) realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) ); + if ( pTmp == 0 ) + { + return sal_False; + } + pFile->m_pWriteBuf = pTmp; + pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len ); + pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2; + memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree); + } + } + + + + memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1); +#ifdef DEBUG_OSL_PROFILE + strLen = strlen(pFile->m_pWriteBuf); +#endif + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\r'; + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\n'; + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 2]='\0'; + + pFile->m_nWriteBufFree-=Len+2; + +#ifdef DEBUG_OSL_PROFILE +/* OSL_TRACE("File Buffer in _putLine '%s' '%i'(%i)\n",pFile->m_pWriteBuf,strlen(pFile->m_pWriteBuf),pFile->m_nWriteBufLen - pFile->m_nWriteBufFree);*/ +#endif + + return (sal_True); +} + +/* platform specific end */ + + +static const sal_Char* stripBlanks(const sal_Char* String, sal_uInt32* pLen) +{ + if ( (pLen != NULL) && ( *pLen != 0 ) ) + { + while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t')) + (*pLen)--; + + while ((*String == ' ') || (*String == '\t')) + { + String++; + (*pLen)--; + } + } + else + while ((*String == ' ') || (*String == '\t')) + String++; + + return (String); +} + +static const sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == NULL) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *)); + memset(pProfile->m_Lines,0,pProfile->m_MaxLines * sizeof(sal_Char *)); + } + else + { + unsigned int index=0; + unsigned int oldmax=pProfile->m_MaxLines; + + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, pProfile->m_MaxLines * sizeof(sal_Char *)); + + for ( index = oldmax ; index < pProfile->m_MaxLines ; ++index ) + { + pProfile->m_Lines[index]=0; + } + } + + if (pProfile->m_Lines == NULL) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return (NULL); + } + + } + + if ( pProfile->m_Lines != 0 && pProfile->m_Lines[pProfile->m_NoLines] != 0 ) + { + free(pProfile->m_Lines[pProfile->m_NoLines]); + } + pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line); + + return (pProfile->m_Lines[pProfile->m_NoLines - 1]); +} + +static const sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == NULL) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *)); + memset(pProfile->m_Lines,0,pProfile->m_MaxLines * sizeof(sal_Char *)); + } + else + { + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(sal_Char *)); + + memset(&pProfile->m_Lines[pProfile->m_NoLines], + 0, + (pProfile->m_MaxLines - pProfile->m_NoLines - 1) * sizeof(sal_Char*)); + } + + if (pProfile->m_Lines == NULL) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return (NULL); + } + } + + LineNo = LineNo > pProfile->m_NoLines ? pProfile->m_NoLines : LineNo; + + if (LineNo < pProfile->m_NoLines) + { + sal_uInt32 i, n; + osl_TProfileSection* pSec; + + memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo], + (pProfile->m_NoLines - LineNo) * sizeof(sal_Char *)); + + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line >= LineNo) + pSec->m_Line++; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line >= LineNo) + pSec->m_Entries[n].m_Line++; + } + } + + pProfile->m_NoLines++; + + pProfile->m_Lines[LineNo] = strdup(Line); + + return (pProfile->m_Lines[LineNo]); +} + +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo) +{ + if (LineNo < pProfile->m_NoLines) + { + free(pProfile->m_Lines[LineNo]); + pProfile->m_Lines[LineNo]=0; + if (pProfile->m_NoLines - LineNo > 1) + { + sal_uInt32 i, n; + osl_TProfileSection* pSec; + + memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1], + (pProfile->m_NoLines - LineNo - 1) * sizeof(sal_Char *)); + + memset(&pProfile->m_Lines[pProfile->m_NoLines - 1], + 0, + (pProfile->m_MaxLines - pProfile->m_NoLines) * sizeof(sal_Char*)); + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line > LineNo) + pSec->m_Line--; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line > LineNo) + pSec->m_Entries[n].m_Line--; + } + } + else + { + pProfile->m_Lines[LineNo] = 0; + } + + pProfile->m_NoLines--; + } + + return; +} + +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + const sal_Char* Entry, sal_uInt32 Len) +{ + Entry = stripBlanks(Entry, &Len); + pSection->m_Entries[NoEntry].m_Line = Line; + pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line]; + pSection->m_Entries[NoEntry].m_Len = Len; + + return; +} + +static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, const sal_Char* Entry, sal_uInt32 Len) +{ + if (pSection != NULL) + { + if (pSection->m_NoEntries >= pSection->m_MaxEntries) + { + if (pSection->m_Entries == NULL) + { + pSection->m_MaxEntries = ENTRIES_INI; + pSection->m_Entries = (osl_TProfileEntry *)malloc( + pSection->m_MaxEntries * sizeof(osl_TProfileEntry)); + } + else + { + pSection->m_MaxEntries += ENTRIES_ADD; + pSection->m_Entries = (osl_TProfileEntry *)realloc(pSection->m_Entries, + pSection->m_MaxEntries * sizeof(osl_TProfileEntry)); + } + + if (pSection->m_Entries == NULL) + { + pSection->m_NoEntries = 0; + pSection->m_MaxEntries = 0; + return (sal_False); + } + } + + pSection->m_NoEntries++; + + Entry = stripBlanks(Entry, &Len); + setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line, + Entry, Len); + + return (sal_True); + } + + return (sal_False); +} + +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry) +{ + if (NoEntry < pSection->m_NoEntries) + { + if (pSection->m_NoEntries - NoEntry > 1) + { + memmove(&pSection->m_Entries[NoEntry], + &pSection->m_Entries[NoEntry + 1], + (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry)); + pSection->m_Entries[pSection->m_NoEntries - 1].m_Line=0; + pSection->m_Entries[pSection->m_NoEntries - 1].m_Offset=0; + pSection->m_Entries[pSection->m_NoEntries - 1].m_Len=0; + } + + pSection->m_NoEntries--; + } + + return; +} + +static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len) +{ + if (pProfile->m_NoSections >= pProfile->m_MaxSections) + { + if (pProfile->m_Sections == NULL) + { + pProfile->m_MaxSections = SECTIONS_INI; + pProfile->m_Sections = (osl_TProfileSection *)malloc(pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + memset(pProfile->m_Sections,0,pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + } + else + { + unsigned int index=0; + unsigned int oldmax=pProfile->m_MaxSections; + + pProfile->m_MaxSections += SECTIONS_ADD; + pProfile->m_Sections = (osl_TProfileSection *)realloc(pProfile->m_Sections, + pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + for ( index = oldmax ; index < pProfile->m_MaxSections ; ++index ) + { + pProfile->m_Sections[index].m_Entries=0; + } + } + + if (pProfile->m_Sections == NULL) + { + pProfile->m_NoSections = 0; + pProfile->m_MaxSections = 0; + return (sal_False); + } + } + + pProfile->m_NoSections++; + + if ( pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries != 0 ) + { + free(pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries); + } + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = NULL; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries = 0; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0; + + Section = (sal_Char *)stripBlanks(Section, &Len); + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line]; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len; + + return (sal_True); +} + +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection) +{ + sal_uInt32 Section; + + if ((Section = pSection - pProfile->m_Sections) < pProfile->m_NoSections) + { + free (pSection->m_Entries); + pSection->m_Entries=0; + if (pProfile->m_NoSections - Section > 1) + { + memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1], + (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection)); + + memset(&pProfile->m_Sections[pProfile->m_NoSections - 1], + 0, + (pProfile->m_MaxSections - pProfile->m_NoSections) * sizeof(osl_TProfileSection)); + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = 0; + } + else + { + pSection->m_Entries = 0; + } + + pProfile->m_NoSections--; + } + + return; +} + +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section, + const sal_Char* Entry, sal_uInt32 *pNoEntry) +{ +static sal_uInt32 Sect = 0; + sal_uInt32 i, n; + sal_uInt32 Len; + const sal_Char* pStr; + osl_TProfileSection* pSec = NULL; + + Len = strlen(Section); + Section = (sal_Char *)stripBlanks(Section, &Len); + + n = Sect; + + for (i = 0; i < pProfile->m_NoSections; i++) + { + n %= pProfile->m_NoSections; + pSec = &pProfile->m_Sections[n]; + if ((Len == pSec->m_Len) && + (strnicmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len) + == 0)) + break; + n++; + } + + Sect = n; + + if (i < pProfile->m_NoSections) + { + Len = strlen(Entry); + Entry = stripBlanks(Entry, &Len); + + *pNoEntry = pSec->m_NoEntries; + + for (i = 0; i < pSec->m_NoEntries; i++) + { + pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset]; + if ((Len == pSec->m_Entries[i].m_Len) && + (strnicmp(Entry, pStr, pSec->m_Entries[i].m_Len) + == 0)) + { + *pNoEntry = i; + break; + } + } + } + else + pSec = NULL; + + return (pSec); +} + +static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile) +{ + sal_uInt32 i; + sal_Char* pStr; + sal_Char* pChar; + sal_Char Line[4096]; + + pProfile->m_NoLines = 0; + pProfile->m_NoSections = 0; + + OSL_VERIFY(rewindFile(pFile, sal_False)); + + while (getLine(pFile, Line, sizeof(Line))) + { + if (! addLine(pProfile, Line)) + return (sal_False); + } + + for (i = 0; i < pProfile->m_NoLines; i++) + { + pStr = (sal_Char *)stripBlanks(pProfile->m_Lines[i], NULL); + + if ((*pStr == '\0') || (*pStr == ';')) + continue; + + if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == NULL) || + ((pChar - pStr) <= 2)) + { + /* insert entry */ + + if (pProfile->m_NoSections < 1) + continue; + + if ((pChar = strchr(pStr, '=')) == NULL) + pChar = pStr + strlen(pStr); + + if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1], + i, pStr, pChar - pStr)) + return (sal_False); + } + else + { + /* new section */ + + if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1)) + return (sal_False); + } + } + + return (sal_True); +} + + + + + +static sal_Bool storeProfile(osl_TProfileImpl* pProfile, sal_Bool bCleanup) +{ +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In storeProfile\n"); +#endif + + if (pProfile->m_Lines != NULL) + { + if (pProfile->m_Flags & FLG_MODIFIED) + { + sal_uInt32 i; + + osl_TFile* pTmpFile = osl_openTmpProfileImpl(pProfile); + + if ( pTmpFile == 0 ) + { + return sal_False; + } + + OSL_VERIFY(rewindFile(pTmpFile, sal_True)); + + for (i = 0; i < pProfile->m_NoLines; i++) + { + OSL_VERIFY(putLine(pTmpFile, pProfile->m_Lines[i])); + } + + if ( ! writeProfileImpl(pTmpFile) ) + { + if ( pTmpFile->m_pWriteBuf != 0 ) + { + free(pTmpFile->m_pWriteBuf); + } + + pTmpFile->m_pWriteBuf=0; + pTmpFile->m_nWriteBufLen=0; + pTmpFile->m_nWriteBufFree=0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out storeProfile [not flushed]\n"); +#endif + closeFileImpl(pTmpFile); + + return sal_False; + } + + pProfile->m_Flags &= ~FLG_MODIFIED; + + closeFileImpl(pProfile->m_pFile); + closeFileImpl(pTmpFile); + + osl_ProfileSwapProfileNames(pProfile); + +/* free(pProfile->m_pFile);*/ +/* free(pTmpFile);*/ + + pProfile->m_pFile = openFileImpl(pProfile->m_strFileName,pProfile->m_Flags); + + } + + if (bCleanup) + { + while (pProfile->m_NoLines > 0) + removeLine(pProfile, pProfile->m_NoLines - 1); + + free(pProfile->m_Lines); + pProfile->m_Lines = NULL; + pProfile->m_MaxLines = 0; + + while (pProfile->m_NoSections > 0) + removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]); + + free(pProfile->m_Sections); + pProfile->m_Sections = NULL; + pProfile->m_MaxSections = 0; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out storeProfile [ok]\n"); +#endif + return (sal_True); +} + + +static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl* pProfile) +{ + osl_TFile* pFile=0; + rtl_uString* ustrExtension=0; + rtl_uString* ustrTmpName=0; + oslProfileOption PFlags=0; + + rtl_uString_newFromAscii(&ustrExtension,"tmp"); + + + /* generate tmp profilename */ + ustrTmpName=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension); + rtl_uString_release(ustrExtension); + + if ( ustrTmpName == 0 ) + { + return 0; + } + + + if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) ) + { + PFlags |= osl_Profile_WRITELOCK; + } + + /* open this file */ + pFile = openFileImpl(ustrTmpName,pProfile->m_Flags | PFlags); + + + /* return new pFile */ + return pFile; +} + + +static sal_Bool osl_ProfileSwapProfileNames(osl_TProfileImpl* pProfile) +{ + sal_Bool bRet = sal_False; + + rtl_uString* ustrBakFile=0; + rtl_uString* ustrTmpFile=0; + rtl_uString* ustrIniFile=0; + rtl_uString* ustrExtension=0; + + + rtl_uString_newFromAscii(&ustrExtension,"bak"); + + ustrBakFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension); + rtl_uString_release(ustrExtension); + ustrExtension=0; + + + rtl_uString_newFromAscii(&ustrExtension,"ini"); + + ustrIniFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension); + rtl_uString_release(ustrExtension); + ustrExtension=0; + + + rtl_uString_newFromAscii(&ustrExtension,"tmp"); + + ustrTmpFile=osl_ProfileGenerateExtension(pProfile->m_strFileName,ustrExtension); + rtl_uString_release(ustrExtension); + ustrExtension=0; + + + /* unlink bak */ + DeleteFileW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrBakFile )) ); + + /* rename ini bak */ + MoveFileExW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrIniFile )), reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrBakFile )), MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH ); + + /* rename tmp ini */ + MoveFileExW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrTmpFile )), reinterpret_cast<LPCWSTR>(rtl_uString_getStr( ustrIniFile )), MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH ); + + return bRet; +} + + +static rtl_uString* osl_ProfileGenerateExtension(rtl_uString* ustrFileName, rtl_uString* ustrExtension) +{ + rtl_uString* ustrNewFileName=0; + rtl_uString* ustrOldExtension = 0; + sal_Unicode* pExtensionBuf = 0; + sal_Unicode* pFileNameBuf = 0; + sal_Int32 nIndex = -1; + + pFileNameBuf = rtl_uString_getStr(ustrFileName); + + rtl_uString_newFromAscii(&ustrOldExtension,"."); + + pExtensionBuf = rtl_uString_getStr(ustrOldExtension); + + nIndex = rtl_ustr_lastIndexOfChar(pFileNameBuf,*pExtensionBuf); + + rtl_uString_newReplaceStrAt(&ustrNewFileName, + ustrFileName, + nIndex+1, + 3, + ustrExtension); + + return ustrNewFileName; +} + + +static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile; + oslProfileOption PFlags=0; + + + if ( bWriteable ) + { +/* PFlags = osl_Profile_DEFAULT | osl_Profile_READWRITE; */ + PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK; + } + else + { + PFlags = osl_Profile_DEFAULT; + } + + + if (pProfile == NULL) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("AUTOOPEN MODE\n"); +#endif + + + + if ( ( pProfile = (osl_TProfileImpl*)osl_openProfile( NULL, PFlags ) ) != NULL ) + { + pProfile->m_Flags |= FLG_AUTOOPEN; + } + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("try to acquire\n"); +#endif + + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | + osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE))) + { + osl_TStamp Stamp; +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("DEFAULT MODE\n"); +#endif + pProfile->m_pFile = openFileImpl( + pProfile->m_strFileName, pProfile->m_Flags | PFlags); + if (!pProfile->m_pFile) + return NULL; + + Stamp = getFileStamp(pProfile->m_pFile); + + if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp))) + { + pProfile->m_Stamp = Stamp; + + loadProfile(pProfile->m_pFile, pProfile); + } + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("READ/WRITELOCK MODE\n"); +#endif + + + /* A readlock file could not be written */ + if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable) + { + return (NULL); + } + } + } + } + + return (pProfile); +} + +static sal_Bool releaseProfile(osl_TProfileImpl* pProfile) +{ +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In releaseProfile\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [profile==0]\n"); +#endif + return sal_False; + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (pProfile->m_Flags & FLG_AUTOOPEN) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [AUTOOPEN]\n"); +#endif + return (osl_closeProfile((oslProfile)pProfile)); + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("DEFAULT MODE\n"); +#endif + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | + osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE))) + { + if (pProfile->m_Flags & FLG_MODIFIED) + storeProfile(pProfile, sal_False); + + closeFileImpl(pProfile->m_pFile); + pProfile->m_pFile = NULL; + } + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [ok]\n"); +#endif + return (sal_True); +} + +static sal_Bool lookupProfile(const sal_Unicode *strPath, const sal_Unicode *strFile, sal_Unicode *strProfile) +{ + sal_Char *pChr, *pStr; + sal_Char Buffer[4096] = ""; + sal_Char Product[132] = ""; + + ::osl::LongPathBuffer< sal_Unicode > aPath( MAX_LONG_PATH ); + aPath[0] = 0; + DWORD dwPathLen = 0; + + if (*strPath == L'"') + { + int i = 0; + + strPath++; + + while ((strPath[i] != L'"') && (strPath[i] != L'\0')) + i++; + + WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(strPath), i, Product, sizeof(Product), NULL, NULL); + Product[i] = '\0'; + strPath += i; + + if (*strPath == L'"') + strPath++; + + if ( (*strPath == L'/') || (*strPath == L'\\') ) + { + strPath++; + } + } + + else + { + /* if we have not product identfication, do a special handling for soffice.ini */ + if (rtl_ustr_ascii_compare(strFile, SVERSION_PROFILE) == 0) + { + rtl_uString * strSVProfile = NULL; + rtl_uString * strSVFallback = NULL; + rtl_uString * strSVLocation = NULL; + rtl_uString * strSVName = NULL; + ::osl::LongPathBuffer< sal_Char > aDir( MAX_LONG_PATH ); + oslProfile hProfile; + + rtl_uString_newFromAscii(&strSVFallback, SVERSION_FALLBACK); + rtl_uString_newFromAscii(&strSVLocation, SVERSION_LOCATION); + rtl_uString_newFromAscii(&strSVName, SVERSION_NAME); + + /* open sversion.ini in the system directory, and try to locate the entry + with the highest version for StarOffice */ + if (osl_getProfileName( strSVFallback, strSVName, &strSVProfile)) + { + hProfile = osl_openProfile(strSVProfile, osl_Profile_READLOCK); + if (hProfile) + { + osl_getProfileSectionEntries( + hProfile, SVERSION_SECTION, Buffer, sizeof(Buffer)); + + for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1) + { + if ((strnicmp( + pChr, SVERSION_SOFFICE, + sizeof(SVERSION_SOFFICE) - 1) + == 0) + && (stricmp(Product, pChr) < 0)) + { + osl_readProfileString( + hProfile, SVERSION_SECTION, pChr, aDir, + aDir.getBufSizeInSymbols(), ""); + + /* check for existence of path */ + if (access(aDir, 0) >= 0) + strcpy(Product, pChr); + } + } + + osl_closeProfile(hProfile); + } + rtl_uString_release(strSVProfile); + strSVProfile = NULL; + } + + /* open sversion.ini in the users directory, and try to locate the entry + with the highest version for StarOffice */ + if ((strcmp(SVERSION_LOCATION, SVERSION_FALLBACK) != 0) && + (osl_getProfileName(strSVLocation, strSVName, &strSVProfile))) + { + hProfile = osl_openProfile(strSVProfile, osl_Profile_READLOCK); + if (hProfile) + { + osl_getProfileSectionEntries( + hProfile, SVERSION_SECTION, Buffer, sizeof(Buffer)); + + for (pChr = Buffer; *pChr != '\0'; pChr += strlen(pChr) + 1) + { + if ((strnicmp( + pChr, SVERSION_SOFFICE, + sizeof(SVERSION_SOFFICE) - 1) + == 0) + && (stricmp(Product, pChr) < 0)) + { + osl_readProfileString( + hProfile, SVERSION_SECTION, pChr, aDir, + aDir.getBufSizeInSymbols(), ""); + + /* check for existence of path */ + if (access(aDir, 0) >= 0) + strcpy(Product, pChr); + } + } + + osl_closeProfile(hProfile); + } + rtl_uString_release(strSVProfile); + } + + rtl_uString_release(strSVFallback); + rtl_uString_release(strSVLocation); + rtl_uString_release(strSVName); + + /* remove any trailing build number */ + if ((pChr = strrchr(Product, '/')) != NULL) + *pChr = '\0'; + } + } + + /* if we have an userid option eg. "-userid:rh[/usr/home/rh/staroffice]", + this will supercede all other locations */ + { + sal_uInt32 n, nArgs = osl_getCommandArgCount(); + + for (n = 0; n < nArgs; n++) + { + rtl_uString * strCommandArg = NULL; + + if ((osl_getCommandArg( n, &strCommandArg ) == osl_Process_E_None) && + ((strCommandArg->buffer[0] == L'-') || (strCommandArg->buffer[0] == L'+')) && + (rtl_ustr_ascii_compare_WithLength(strCommandArg->buffer, RTL_CONSTASCII_LENGTH(SVERSION_OPTION), SVERSION_OPTION))) + { + sal_Unicode *pCommandArg = strCommandArg->buffer + RTL_CONSTASCII_LENGTH(SVERSION_OPTION); + sal_Int32 nStart, nEnd; + + if (((nStart = rtl_ustr_indexOfChar(pCommandArg, L'[')) != -1) && + ((nEnd = rtl_ustr_indexOfChar(pCommandArg + nStart + 1, L']')) != -1)) + { + dwPathLen = nEnd; + copy_ustr_n(aPath, pCommandArg + nStart + 1, dwPathLen); + aPath[dwPathLen] = 0; + + /* build full path */ + if ((aPath[dwPathLen - 1] != L'/') && (aPath[dwPathLen - 1] != L'\\')) + { + copy_ustr_n(aPath + dwPathLen++, L"/", 2); + } + + if (*strPath) + { + copy_ustr_n(aPath + dwPathLen, strPath, rtl_ustr_getLength(strPath)+1); + dwPathLen += rtl_ustr_getLength(strPath); + } + else + { + ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH ); + int n; + + if ((n = WideCharToMultiByte(CP_ACP,0, ::osl::mingw_reinterpret_cast<LPCWSTR>(aPath), -1, aTmpPath, aTmpPath.getBufSizeInSymbols(), NULL, NULL)) > 0) + { + strcpy(aTmpPath + n, SVERSION_USER); + if (access(aTmpPath, 0) >= 0) + { + dwPathLen += MultiByteToWideChar( CP_ACP, 0, SVERSION_USER, -1, reinterpret_cast<LPWSTR>(aPath + dwPathLen), aPath.getBufSizeInSymbols() - dwPathLen ); + } + } + } + + break; + } + } + } + } + + + if (dwPathLen == 0) + { + rtl_uString * strExecutable = NULL; + rtl_uString * strTmp = NULL; + sal_Int32 nPos; + + /* try to find the file in the directory of the executbale */ + if (osl_getExecutableFile(&strTmp) != osl_Process_E_None) + return (sal_False); + + /* convert to native path */ + if (osl_getSystemPathFromFileURL(strTmp, &strExecutable) != osl_File_E_None) + { + rtl_uString_release(strTmp); + return sal_False; + } + + rtl_uString_release(strTmp); + + /* seperate path from filename */ + if ((nPos = rtl_ustr_lastIndexOfChar(strExecutable->buffer, L'\\')) == -1) + { + if ((nPos = rtl_ustr_lastIndexOfChar(strExecutable->buffer, L':')) == -1) + { + return sal_False; + } + else + { + copy_ustr_n(aPath, strExecutable->buffer, nPos); + aPath[nPos] = 0; + dwPathLen = nPos; + } + } + else + { + copy_ustr_n(aPath, strExecutable->buffer, nPos); + dwPathLen = nPos; + aPath[dwPathLen] = 0; + } + + /* if we have no product identification use the executable file name */ + if (*Product == 0) + { + WideCharToMultiByte(CP_ACP,0, reinterpret_cast<LPCWSTR>(strExecutable->buffer + nPos + 1), -1, Product, sizeof(Product), NULL, NULL); + + /* remove extension */ + if ((pChr = strrchr(Product, '.')) != NULL) + *pChr = '\0'; + } + + rtl_uString_release(strExecutable); + + /* remember last subdir */ + nPos = rtl_ustr_lastIndexOfChar(aPath, L'\\'); + + copy_ustr_n(aPath + dwPathLen++, L"\\", 2); + + if (*strPath) + { + copy_ustr_n(aPath + dwPathLen, strPath, rtl_ustr_getLength(strPath)+1); + dwPathLen += rtl_ustr_getLength(strPath); + } + + { + ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH ); + + WideCharToMultiByte(CP_ACP,0, ::osl::mingw_reinterpret_cast<LPCWSTR>(aPath), -1, aTmpPath, aTmpPath.getBufSizeInSymbols(), NULL, NULL); + + /* if file not exists, remove any specified subdirectories + like "bin" or "program" */ + + if (((access(aTmpPath, 0) < 0) && (nPos != -1)) || (*strPath == 0)) + { + static sal_Char *SubDirs[] = SVERSION_DIRS; + + int i = 0; + pStr = aTmpPath + nPos; + + for (i = 0; i < (sizeof(SubDirs) / sizeof(SubDirs[0])); i++) + if (strnicmp(pStr + 1, SubDirs[i], strlen(SubDirs[i])) == 0) + { + if ( *strPath == 0) + { + strcpy(pStr + 1,SVERSION_USER); + if ( access(aTmpPath, 0) < 0 ) + { + *(pStr+1)='\0'; + } + else + { + dwPathLen = nPos + MultiByteToWideChar( CP_ACP, 0, SVERSION_USER, -1, reinterpret_cast<LPWSTR>(aPath + nPos + 1), aPath.getBufSizeInSymbols() - (nPos + 1) ); + } + } + else + { + copy_ustr_n(aPath + nPos + 1, strPath, rtl_ustr_getLength(strPath)+1); + dwPathLen = nPos + 1 + rtl_ustr_getLength(strPath); + } + + break; + } + } + } + + if ((aPath[dwPathLen - 1] != L'/') && (aPath[dwPathLen - 1] != L'\\')) + { + aPath[dwPathLen++] = L'\\'; + aPath[dwPathLen] = 0; + } + + copy_ustr_n(aPath + dwPathLen, strFile, rtl_ustr_getLength(strFile)+1); + + { + ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH ); + + WideCharToMultiByte(CP_ACP,0, ::osl::mingw_reinterpret_cast<LPCWSTR>(aPath), -1, aTmpPath, aTmpPath.getBufSizeInSymbols(), NULL, NULL); + + if ((access(aTmpPath, 0) < 0) && (strlen(Product) > 0)) + { + rtl_uString * strSVFallback = NULL; + rtl_uString * strSVProfile = NULL; + rtl_uString * strSVLocation = NULL; + rtl_uString * strSVName = NULL; + oslProfile hProfile; + + rtl_uString_newFromAscii(&strSVFallback, SVERSION_FALLBACK); + rtl_uString_newFromAscii(&strSVLocation, SVERSION_LOCATION); + rtl_uString_newFromAscii(&strSVName, SVERSION_NAME); + + /* open sversion.ini in the system directory, and try to locate the entry + with the highest version for StarOffice */ + if (osl_getProfileName(strSVLocation, strSVName, &strSVProfile)) + { + hProfile = osl_openProfile( + strSVProfile, osl_Profile_READLOCK); + if (hProfile) + { + osl_readProfileString( + hProfile, SVERSION_SECTION, Product, Buffer, + sizeof(Buffer), ""); + osl_closeProfile(hProfile); + + /* if not found, try the fallback */ + if ((strlen(Buffer) <= 0) + && (strcmp(SVERSION_LOCATION, SVERSION_FALLBACK) + != 0)) + { + if (osl_getProfileName( + strSVFallback, strSVName, &strSVProfile)) + { + hProfile = osl_openProfile( + strSVProfile, osl_Profile_READLOCK); + if (hProfile) + { + osl_readProfileString( + hProfile, SVERSION_SECTION, Product, + Buffer, sizeof(Buffer), ""); + } + } + + osl_closeProfile(hProfile); + } + + if (strlen(Buffer) > 0) + { + dwPathLen = MultiByteToWideChar( + CP_ACP, 0, Buffer, -1, ::osl::mingw_reinterpret_cast<LPWSTR>(aPath), aPath.getBufSizeInSymbols() ); + dwPathLen -=1; + + /* build full path */ + if ((aPath[dwPathLen - 1] != L'/') + && (aPath[dwPathLen - 1] != L'\\')) + { + copy_ustr_n(aPath + dwPathLen++, L"\\", 2); + } + + if (*strPath) + { + copy_ustr_n(aPath + dwPathLen, strPath, rtl_ustr_getLength(strPath)+1); + dwPathLen += rtl_ustr_getLength(strPath); + } + else + { + ::osl::LongPathBuffer< sal_Char > aTmpPath( MAX_LONG_PATH ); + int n; + + if ((n = WideCharToMultiByte( + CP_ACP,0, ::osl::mingw_reinterpret_cast<LPCWSTR>(aPath), -1, aTmpPath, + aTmpPath.getBufSizeInSymbols(), NULL, NULL)) + > 0) + { + strcpy(aTmpPath + n, SVERSION_USER); + if (access(aTmpPath, 0) >= 0) + { + dwPathLen += MultiByteToWideChar( + CP_ACP, 0, SVERSION_USER, -1, + reinterpret_cast<LPWSTR>(aPath + dwPathLen), + aPath.getBufSizeInSymbols() - dwPathLen ); + } + } + } + } + } + + rtl_uString_release(strSVProfile); + } + + rtl_uString_release(strSVFallback); + rtl_uString_release(strSVLocation); + rtl_uString_release(strSVName); + } + } + + aPath[dwPathLen] = 0; + } + + /* copy filename */ + copy_ustr_n(strProfile, aPath, dwPathLen+1); + + return sal_True; +} + + diff --git a/sal/osl/w32/salinit.cxx b/sal/osl/w32/salinit.cxx new file mode 100644 index 000000000000..aea584f67970 --- /dev/null +++ b/sal/osl/w32/salinit.cxx @@ -0,0 +1,82 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "system.h" +#include <osl/process.h> +#include <sal/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// Prototypes for initialization and deinitialization of SAL library + +void SAL_CALL sal_detail_initialize(int argc, char ** argv) +{ + WSADATA wsaData; + int error; + WORD wVersionRequested; + + wVersionRequested = MAKEWORD(1, 1); + + error = WSAStartup(wVersionRequested, &wsaData); + if ( 0 == error ) + { + WORD wMajorVersionRequired = 1; + WORD wMinorVersionRequired = 1; + + if ((LOBYTE(wsaData.wVersion) < wMajorVersionRequired) || + (LOBYTE(wsaData.wVersion) == wMajorVersionRequired) && + ((HIBYTE(wsaData.wVersion) < wMinorVersionRequired))) + { + // How to handle a very unlikely error ??? + } + } + else + { + // How to handle a very unlikely error ??? + } + + osl_setCommandArgs(argc, argv); +} + +void SAL_CALL sal_detail_deinitialize() +{ + if ( SOCKET_ERROR == WSACleanup() ) + { + // We should never reach this point or we did wrong elsewhere + } +} + + + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sal/osl/w32/secimpl.h b/sal/osl/w32/secimpl.h new file mode 100644 index 000000000000..97a9d9c44f9e --- /dev/null +++ b/sal/osl/w32/secimpl.h @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_SECURITYIMPL_H_ +#define _OSL_SECURITYIMPL_H_ + +#include <winnetwk.h> + +#include <osl/security.h> + +#define USER_BUFFER_SIZE 256 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _oslSecurityImpl { + HANDLE m_hProfile; + HANDLE m_hToken; + sal_Unicode m_User[USER_BUFFER_SIZE]; +/* ts: Erweiterung um Fileserver-login */ + NETRESOURCEW *m_pNetResource; +} oslSecurityImpl; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/w32/security.c b/sal/osl/w32/security.c new file mode 100644 index 000000000000..237ea67dc949 --- /dev/null +++ b/sal/osl/w32/security.c @@ -0,0 +1,991 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/security.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/file.h> +#include <systools/win32/uwinapi.h> +#include "secimpl.h" + +/*****************************************************************************/ +/* Data Type Definition */ +/*****************************************************************************/ + + +/* Data for use in (un)LoadProfile Functions */ +/* Declarations based on USERENV.H for Windows 2000 Beta 2 */ +#define PI_NOUI 0x00000001 // Prevents displaying of messages +#define PI_APPLYPOLICY 0x00000002 // Apply NT4 style policy + +typedef struct _PROFILEINFOW { + DWORD dwSize; // Must be set to sizeof(PROFILEINFO) + DWORD dwFlags; // See flags above + LPWSTR lpUserName; // User name (required) + LPWSTR lpProfilePath; // Roaming profile path + LPWSTR lpDefaultPath; // Default user profile path + LPWSTR lpServerName; // Validating DC name in netbios format + LPWSTR lpPolicyPath; // Path to the NT4 style policy file + HANDLE hProfile; // Registry key handle - filled by function +} PROFILEINFOW, FAR * LPPROFILEINFOW; + +/* Typedefs for function pointers in USERENV.DLL */ +typedef BOOL (STDMETHODCALLTYPE FAR * LPFNLOADUSERPROFILE) ( + HANDLE hToken, + LPPROFILEINFOW lpProfileInfo +); + +typedef BOOL (STDMETHODCALLTYPE FAR * LPFNUNLOADUSERPROFILE) ( + HANDLE hToken, + HANDLE hProfile +); + +typedef BOOL (STDMETHODCALLTYPE FAR * LPFNGETUSERPROFILEDIR) ( + HANDLE hToken, + LPTSTR lpProfileDir, + LPDWORD lpcchSize +); + +/* To get an impersonation token we need to create an impersonation + duplicate so every access token has to be created with duplicate + access rights */ + +#define TOKEN_DUP_QUERY (TOKEN_QUERY|TOKEN_DUPLICATE) + +/*****************************************************************************/ +/* Static Module Function Declarations */ +/*****************************************************************************/ + +static sal_Bool isWNT(void); +static sal_Bool GetSpecialFolder(rtl_uString **strPath,int nFolder); +static BOOL Privilege(LPTSTR pszPrivilege, BOOL bEnable); +static sal_Bool SAL_CALL getUserNameImpl(oslSecurity Security, rtl_uString **strName, sal_Bool bIncludeDomain); + +/*****************************************************************************/ +/* Exported Module Functions */ +/*****************************************************************************/ + +oslSecurity SAL_CALL osl_getCurrentSecurity(void) +{ + oslSecurityImpl* pSecImpl = malloc(sizeof(oslSecurityImpl)); + + pSecImpl->m_pNetResource = NULL; + pSecImpl->m_User[0] = '\0'; + pSecImpl->m_hToken = NULL; + pSecImpl->m_hProfile = NULL; + + return ((oslSecurity)pSecImpl); +} + +oslSecurityError SAL_CALL osl_loginUser( rtl_uString *strUserName, rtl_uString *strPasswd, oslSecurity *pSecurity ) +{ + oslSecurityError ret; + + if (!isWNT()) + { + *pSecurity = osl_getCurrentSecurity(); + ret = osl_Security_E_None; + } + else + { + sal_Unicode* strUser; + sal_Unicode* strDomain = _wcsdup(rtl_uString_getStr(strUserName)); + HANDLE hUserToken; + + #if OSL_DEBUG_LEVEL > 0 + LUID luid; + #endif + + if (NULL != (strUser = wcschr(strDomain, L'/'))) + *strUser++ = L'\0'; + else + { + strUser = strDomain; + strDomain = NULL; + } + + // this process must have the right: 'act as a part of operatingsystem' + OSL_ASSERT(LookupPrivilegeValue(NULL, SE_TCB_NAME, &luid)); + + if (LogonUserW(strUser, strDomain ? strDomain : L"", rtl_uString_getStr(strPasswd), + LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, + &hUserToken)) + { + oslSecurityImpl* pSecImpl = malloc(sizeof(oslSecurityImpl)); + + pSecImpl->m_pNetResource = NULL; + pSecImpl->m_hToken = hUserToken; + pSecImpl->m_hProfile = NULL; + wcscpy(pSecImpl->m_User, strUser); + + *pSecurity = (oslSecurity)pSecImpl; + ret = osl_Security_E_None; + } + else + ret = osl_Security_E_UserUnknown; + + if (strDomain) + free(strDomain); + else + free(strUser); + } + + return ret; +} + +oslSecurityError SAL_CALL osl_loginUserOnFileServer(rtl_uString *strUserName, + rtl_uString *strPasswd, + rtl_uString *strFileServer, + oslSecurity *pSecurity) +{ + oslSecurityError ret; + DWORD err; + NETRESOURCEW netResource; + sal_Unicode* remoteName; + sal_Unicode* userName; + + remoteName = malloc(rtl_uString_getLength(strFileServer) + rtl_uString_getLength(strUserName) + 4); + userName = malloc(rtl_uString_getLength(strFileServer) + rtl_uString_getLength(strUserName) + 2); + + wcscpy(remoteName, L"\\\\"); + wcscat(remoteName, rtl_uString_getStr(strFileServer)); + wcscat(remoteName, L"\\"); + wcscat(remoteName, rtl_uString_getStr(strUserName)); + + wcscpy(userName, rtl_uString_getStr(strFileServer)); + wcscat(userName, L"\\"); + wcscat(userName, rtl_uString_getStr(strUserName)); + + netResource.dwScope = RESOURCE_GLOBALNET; + netResource.dwType = RESOURCETYPE_DISK; + netResource.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; + netResource.dwUsage = RESOURCEUSAGE_CONNECTABLE; + netResource.lpLocalName = NULL; + netResource.lpRemoteName = remoteName; + netResource.lpComment = NULL; + netResource.lpProvider = NULL; + + err = WNetAddConnection2W(&netResource, rtl_uString_getStr(strPasswd), userName, 0); + + if ((err == NO_ERROR) || (err == ERROR_ALREADY_ASSIGNED)) + { + oslSecurityImpl* pSecImpl = malloc(sizeof(oslSecurityImpl)); + + pSecImpl->m_pNetResource = malloc(sizeof(NETRESOURCE)); + *pSecImpl->m_pNetResource = netResource; + + pSecImpl->m_hToken = NULL; + pSecImpl->m_hProfile = NULL; + wcscpy(pSecImpl->m_User, rtl_uString_getStr(strUserName)); + + *pSecurity = (oslSecurity)pSecImpl; + + ret = osl_Security_E_None; + } + else + ret = osl_Security_E_UserUnknown; + + free(remoteName); + free(userName); + + return ret; +} + + +static BOOL WINAPI CheckTokenMembership_Stub( HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember ) +{ + typedef BOOL (WINAPI *CheckTokenMembership_PROC)( HANDLE, PSID, PBOOL ); + + static HMODULE hModule = NULL; + static CheckTokenMembership_PROC pCheckTokenMembership = NULL; + + if ( !hModule ) + { + /* SAL is always linked against ADVAPI32 so we can rely on that it is already mapped */ + + hModule = GetModuleHandleA( "ADVAPI32.DLL" ); + + pCheckTokenMembership = (CheckTokenMembership_PROC)GetProcAddress( hModule, "CheckTokenMembership" ); + } + + if ( pCheckTokenMembership ) + return pCheckTokenMembership( TokenHandle, SidToCheck, IsMember ); + else + { + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; + } + +} + + +sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security) +{ + if (Security != NULL) + { + /* ts: on Window 95 systems any user seems to be an adminstrator */ + if (!isWNT()) + { + return(sal_True); + } + else + { + HANDLE hImpersonationToken = NULL; + PSID psidAdministrators; + SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; + sal_Bool bSuccess = sal_False; + + + /* If Security contains an access token we need to duplicate it to an impersonation + access token. NULL works with CheckTokenMembership() as the current effective + impersonation token + */ + + if ( ((oslSecurityImpl*)Security)->m_hToken ) + { + if ( !DuplicateToken (((oslSecurityImpl*)Security)->m_hToken, SecurityImpersonation, &hImpersonationToken) ) + return sal_False; + } + + /* CheckTokenMembership() can be used on W2K and higher (NT4 no longer supported by OOo) + and also works on Vista to retrieve the effective user rights. Just checking for + membership of Administrators group is not enough on Vista this would require additional + complicated checks as described in KB arcticle Q118626: http://support.microsoft.com/kb/118626/en-us + */ + + if (AllocateAndInitializeSid(&siaNtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &psidAdministrators)) + { + BOOL fSuccess = FALSE; + + if ( CheckTokenMembership_Stub( hImpersonationToken, psidAdministrators, &fSuccess ) && fSuccess ) + bSuccess = sal_True; + + FreeSid(psidAdministrators); + } + + if ( hImpersonationToken ) + CloseHandle( hImpersonationToken ); + + return (bSuccess); + } + } + else + return (sal_False); +} + + +void SAL_CALL osl_freeSecurityHandle(oslSecurity Security) +{ + if (Security) + { + oslSecurityImpl *pSecImpl = (oslSecurityImpl*)Security; + + if (pSecImpl->m_pNetResource != NULL) + { + WNetCancelConnection2W(pSecImpl->m_pNetResource->lpRemoteName, 0, sal_True); + + free(pSecImpl->m_pNetResource->lpRemoteName); + free(pSecImpl->m_pNetResource); + } + + if (pSecImpl->m_hToken) + CloseHandle(pSecImpl->m_hToken); + + if ( pSecImpl->m_hProfile ) + CloseHandle(pSecImpl->m_hProfile); + + free (pSecImpl); + } +} + + +sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **strIdent) +{ + if (Security != NULL) + { + oslSecurityImpl *pSecImpl = (oslSecurityImpl*)Security; + + HANDLE hAccessToken = pSecImpl->m_hToken; + + if (hAccessToken == NULL) + OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY, &hAccessToken); + + if (hAccessToken) + { + sal_Char *Ident; + DWORD nInfoBuffer = 512; + UCHAR* pInfoBuffer = malloc(nInfoBuffer); + + + while (!GetTokenInformation(hAccessToken, TokenUser, + pInfoBuffer, nInfoBuffer, &nInfoBuffer)) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + pInfoBuffer = realloc(pInfoBuffer, nInfoBuffer); + else + { + free(pInfoBuffer); + pInfoBuffer = NULL; + break; + } + } + + if (pSecImpl->m_hToken == NULL) + CloseHandle(hAccessToken); + + if (pInfoBuffer) + { + PSID pSid = ((PTOKEN_USER)pInfoBuffer)->User.Sid; + PSID_IDENTIFIER_AUTHORITY psia; + DWORD dwSubAuthorities; + DWORD dwSidRev=SID_REVISION; + DWORD dwCounter; + DWORD dwSidSize; + + /* obtain SidIdentifierAuthority */ + psia=GetSidIdentifierAuthority(pSid); + + /* obtain sidsubauthority count */ + dwSubAuthorities=min(*GetSidSubAuthorityCount(pSid), 5); + + /* buffer length: S-SID_REVISION- + identifierauthority- + subauthorities- + NULL */ + Ident=malloc(88*sizeof(sal_Char)); + + /* prepare S-SID_REVISION- */ + dwSidSize=wsprintf(Ident, TEXT("S-%lu-"), dwSidRev); + + /* prepare SidIdentifierAuthority */ + if ((psia->Value[0] != 0) || (psia->Value[1] != 0)) + { + dwSidSize+=wsprintf(Ident + strlen(Ident), + TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"), + (USHORT)psia->Value[0], + (USHORT)psia->Value[1], + (USHORT)psia->Value[2], + (USHORT)psia->Value[3], + (USHORT)psia->Value[4], + (USHORT)psia->Value[5]); + } + else + { + dwSidSize+=wsprintf(Ident + strlen(Ident), + TEXT("%lu"), + (ULONG)(psia->Value[5] ) + + (ULONG)(psia->Value[4] << 8) + + (ULONG)(psia->Value[3] << 16) + + (ULONG)(psia->Value[2] << 24) ); + } + + /* loop through SidSubAuthorities */ + for (dwCounter=0; dwCounter < dwSubAuthorities; dwCounter++) + { + dwSidSize+=wsprintf(Ident + dwSidSize, TEXT("-%lu"), + *GetSidSubAuthority(pSid, dwCounter) ); + } + + rtl_uString_newFromAscii( strIdent, Ident ); + + free(pInfoBuffer); + free(Ident); + + return (sal_True); + } + } + else + { + DWORD needed=0; + sal_Unicode *Ident; + + WNetGetUserA(NULL, NULL, &needed); + needed = max( 16 , needed ); + Ident=malloc(needed*sizeof(sal_Unicode)); + + if (WNetGetUserW(NULL, Ident, &needed) != NO_ERROR) + { + wcscpy(Ident, L"unknown"); + Ident[7] = L'\0'; + } + + rtl_uString_newFromStr( strIdent, Ident); + + free(Ident); + + return sal_True; + } + } + + return sal_False; +} + + + +sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **strName) +{ + return getUserNameImpl(Security, strName, sal_True); +} + + +sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory) +{ + rtl_uString *ustrSysDir = NULL; + sal_Bool bSuccess = sal_False; + + if (Security != NULL) + { + oslSecurityImpl *pSecImpl = (oslSecurityImpl*)Security; + + if (pSecImpl->m_pNetResource != NULL) + { + rtl_uString_newFromStr( &ustrSysDir, pSecImpl->m_pNetResource->lpRemoteName); + + bSuccess = (sal_Bool)(osl_File_E_None == osl_getFileURLFromSystemPath( ustrSysDir, pustrDirectory )); + } + else + { +#if 0 + if (pSecImpl->m_hToken) + { + DWORD nInfoBuffer = 512; + UCHAR* pInfoBuffer = malloc(nInfoBuffer); + + while (!GetTokenInformation(pSecImpl->m_hToken, TokenUser, + pInfoBuffer, nInfoBuffer, &nInfoBuffer)) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + pInfoBuffer = realloc(pInfoBuffer, nInfoBuffer); + else + { + free(pInfoBuffer); + pInfoBuffer = NULL; + break; + } + } + + /* not implemented */ + OSL_ASSERT(sal_False); + + if (pInfoBuffer) + { + /* if (EqualSid() ... */ + + } + } + else +#endif + + bSuccess = (sal_Bool)(GetSpecialFolder(&ustrSysDir, CSIDL_PERSONAL) && + (osl_File_E_None == osl_getFileURLFromSystemPath(ustrSysDir, pustrDirectory))); + } + } + + if ( ustrSysDir ) + rtl_uString_release( ustrSysDir ); + + return bSuccess; +} + +sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory) +{ + sal_Bool bSuccess = sal_False; + + if (Security != NULL) + { + oslSecurityImpl *pSecImpl = (oslSecurityImpl*)Security; + + if (pSecImpl->m_pNetResource != NULL) + { + rtl_uString *ustrSysDir = NULL; + + rtl_uString_newFromStr( &ustrSysDir, pSecImpl->m_pNetResource->lpRemoteName); + bSuccess = (sal_Bool)(osl_File_E_None == osl_getFileURLFromSystemPath( ustrSysDir, pustrDirectory)); + + if ( ustrSysDir ) + rtl_uString_release( ustrSysDir ); + } + else + { + if (pSecImpl->m_hToken) + { + /* not implemented */ + OSL_ASSERT(sal_False); + } + else + { + rtl_uString *ustrFile = NULL; + sal_Unicode sFile[_MAX_PATH]; + + if ( !GetSpecialFolder( &ustrFile, CSIDL_APPDATA) ) + { + OSL_VERIFY(GetWindowsDirectoryW(sFile, _MAX_DIR) > 0); + + rtl_uString_newFromStr( &ustrFile, sFile); + } + + bSuccess = (sal_Bool)(osl_File_E_None == osl_getFileURLFromSystemPath(ustrFile, pustrDirectory)); + + if ( ustrFile ) + rtl_uString_release( ustrFile ); + } + } + } + + return bSuccess; +} + + +sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security) +{ + /* CreateProcessAsUser does not load the specified user's profile + into the HKEY_USERS registry key. This means that access to information + in the HKEY_CURRENT_USER registry key may not produce results consistent + with a normal interactive logon. + It is your responsibility to load the user's registry hive into HKEY_USERS + with the LoadUserProfile function before calling CreateProcessAsUser. + */ + BOOL bOk = FALSE; + + RegCloseKey(HKEY_CURRENT_USER); + + if (Privilege(SE_RESTORE_NAME, TRUE)) + { + HMODULE hUserEnvLib = NULL; + LPFNLOADUSERPROFILE fLoadUserProfile = NULL; + LPFNUNLOADUSERPROFILE fUnloadUserProfile = NULL; + HANDLE hAccessToken = ((oslSecurityImpl*)Security)->m_hToken; + DWORD nError = 0; + + /* try to create user profile */ + if ( !hAccessToken ) + { + /* retrieve security handle if not done before e.g. osl_getCurrentSecurity() + */ + HANDLE hProcess = GetCurrentProcess(); + + if (hProcess != NULL) + { + OpenProcessToken(hProcess, TOKEN_IMPERSONATE, &hAccessToken); + CloseHandle(hProcess); + } + } + + hUserEnvLib = LoadLibraryA("userenv.dll"); + + if (hUserEnvLib) + { + fLoadUserProfile = (LPFNLOADUSERPROFILE)GetProcAddress(hUserEnvLib, "LoadUserProfileW"); + fUnloadUserProfile = (LPFNUNLOADUSERPROFILE)GetProcAddress(hUserEnvLib, "UnloadUserProfile"); + + if (fLoadUserProfile && fUnloadUserProfile) + { + rtl_uString *buffer = 0; + PROFILEINFOW pi; + + getUserNameImpl(Security, &buffer, sal_False); + + ZeroMemory( &pi, sizeof(pi) ); + pi.dwSize = sizeof(pi); + pi.lpUserName = rtl_uString_getStr(buffer); + pi.dwFlags = PI_NOUI; + + if (fLoadUserProfile(hAccessToken, &pi)) + { + fUnloadUserProfile(hAccessToken, pi.hProfile); + + bOk = TRUE; + } + else + nError = GetLastError(); + + rtl_uString_release(buffer); + } + + FreeLibrary(hUserEnvLib); + } + + if (hAccessToken && (hAccessToken != ((oslSecurityImpl*)Security)->m_hToken)) + CloseHandle(hAccessToken); + } + + return (sal_Bool)bOk; +} + + +void SAL_CALL osl_unloadUserProfile(oslSecurity Security) +{ + if ( ((oslSecurityImpl*)Security)->m_hProfile != NULL ) + { + HMODULE hUserEnvLib = NULL; + LPFNLOADUSERPROFILE fLoadUserProfile = NULL; + LPFNUNLOADUSERPROFILE fUnloadUserProfile = NULL; + BOOL bOk = FALSE; + HANDLE hAccessToken = ((oslSecurityImpl*)Security)->m_hToken; + + if ( !hAccessToken ) + { + /* retrieve security handle if not done before e.g. osl_getCurrentSecurity() + */ + HANDLE hProcess = GetCurrentProcess(); + + if (hProcess != NULL) + { + OpenProcessToken(hProcess, TOKEN_IMPERSONATE, &hAccessToken); + CloseHandle(hProcess); + } + } + + hUserEnvLib = LoadLibrary("userenv.dll"); + + if (hUserEnvLib) + { + fLoadUserProfile = (LPFNLOADUSERPROFILE)GetProcAddress(hUserEnvLib, "LoadUserProfileA"); + fUnloadUserProfile = (LPFNUNLOADUSERPROFILE)GetProcAddress(hUserEnvLib, "UnloadUserProfile"); + + if (fLoadUserProfile && fUnloadUserProfile) + { + /* unloading the user profile */ + if (fLoadUserProfile && fUnloadUserProfile) + bOk = fUnloadUserProfile(hAccessToken, ((oslSecurityImpl*)Security)->m_hProfile); + + if (hUserEnvLib) + FreeLibrary(hUserEnvLib); + } + } + + ((oslSecurityImpl*)Security)->m_hProfile; + + if (hAccessToken && (hAccessToken != ((oslSecurityImpl*)Security)->m_hToken)) + { + CloseHandle(hAccessToken); + } + } +} + +/*****************************************************************************/ +/* Static Module Functions */ +/*****************************************************************************/ + + +static sal_Bool GetSpecialFolder(rtl_uString **strPath, int nFolder) +{ + sal_Bool bRet = sal_False; + HINSTANCE hLibrary; + sal_Char PathA[_MAX_PATH]; + sal_Unicode PathW[_MAX_PATH]; + + if ((hLibrary = LoadLibrary("shell32.dll")) != NULL) + { + BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL); + BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL); + + pSHGetSpecialFolderPathA = (BOOL (WINAPI *)(HWND, LPSTR, int, BOOL))GetProcAddress(hLibrary, "SHGetSpecialFolderPathA"); + pSHGetSpecialFolderPathW = (BOOL (WINAPI *)(HWND, LPWSTR, int, BOOL))GetProcAddress(hLibrary, "SHGetSpecialFolderPathW"); + + if (pSHGetSpecialFolderPathA) + { + if (pSHGetSpecialFolderPathA(GetActiveWindow(), PathA, nFolder, TRUE)) + { + rtl_string2UString( strPath, PathA, strlen(PathA), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS); + OSL_ASSERT(*strPath != NULL); + bRet = sal_True; + } + } + else if (pSHGetSpecialFolderPathW) + { + if (pSHGetSpecialFolderPathW(GetActiveWindow(), PathW, nFolder, TRUE)) + { + rtl_uString_newFromStr( strPath, PathW); + bRet = sal_True; + } + } + else + { + HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *) = (HRESULT (WINAPI *)(HWND, int, LPITEMIDLIST *))GetProcAddress(hLibrary, "SHGetSpecialFolderLocation"); + BOOL (WINAPI *pSHGetPathFromIDListA)(LPCITEMIDLIST, LPSTR) = (BOOL (WINAPI *)(LPCITEMIDLIST, LPSTR))GetProcAddress(hLibrary, "SHGetPathFromIDListA"); + BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST, LPWSTR) = (BOOL (WINAPI *)(LPCITEMIDLIST, LPWSTR))GetProcAddress(hLibrary, "SHGetPathFromIDListW"); + HRESULT (WINAPI *pSHGetMalloc)(LPMALLOC *) = (HRESULT (WINAPI *)(LPMALLOC *))GetProcAddress(hLibrary, "SHGetMalloc"); + + + if (pSHGetSpecialFolderLocation && (pSHGetPathFromIDListA || pSHGetPathFromIDListW ) && pSHGetMalloc ) + { + LPITEMIDLIST pidl; + LPMALLOC pMalloc; + HRESULT hr; + + hr = pSHGetSpecialFolderLocation(GetActiveWindow(), nFolder, &pidl); + + /* Get SHGetSpecialFolderLocation fails if directory does not exists. */ + /* If it fails we try to create the directory and redo the call */ + if (! SUCCEEDED(hr)) + { + HKEY hRegKey; + + if (RegOpenKey(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", + &hRegKey) == ERROR_SUCCESS) + { + LONG lRet; + DWORD lSize = elementsof(PathA); + DWORD Type = REG_SZ; + + switch (nFolder) + { + case CSIDL_APPDATA: + lRet = RegQueryValueEx(hRegKey, "AppData", NULL, &Type, (LPBYTE)PathA, &lSize); + break; + + case CSIDL_PERSONAL: + lRet = RegQueryValueEx(hRegKey, "Personal", NULL, &Type, (LPBYTE)PathA, &lSize); + break; + + default: + lRet = -1l; + } + + if ((lRet == ERROR_SUCCESS) && (Type == REG_SZ)) + { + if (_access(PathA, 0) < 0) + CreateDirectory(PathA, NULL); + + hr = pSHGetSpecialFolderLocation(GetActiveWindow(), nFolder, &pidl); + } + + RegCloseKey(hRegKey); + } + } + + if (SUCCEEDED(hr)) + { + if (pSHGetPathFromIDListW && pSHGetPathFromIDListW(pidl, PathW)) + { + /* if directory does not exist, create it */ + if (_waccess(PathW, 0) < 0) + CreateDirectoryW(PathW, NULL); + + rtl_uString_newFromStr( strPath, PathW); + bRet = sal_True; + } + else if (pSHGetPathFromIDListA && pSHGetPathFromIDListA(pidl, PathA)) + { + /* if directory does not exist, create it */ + if (_access(PathA, 0) < 0) + CreateDirectoryA(PathA, NULL); + + rtl_string2UString( strPath, PathA, strlen(PathA), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS); + OSL_ASSERT(*strPath != NULL); + bRet = sal_True; + } + } + + if (SUCCEEDED(pSHGetMalloc(&pMalloc))) + { + pMalloc->lpVtbl->Free(pMalloc, pidl); + pMalloc->lpVtbl->Release(pMalloc); + } + } + } + } + + FreeLibrary(hLibrary); + + return (bRet); +} + + +static sal_Bool isWNT(void) +{ + static sal_Bool isInit = sal_False; + static sal_Bool isWNT = sal_False; + + if (!isInit) + { + OSVERSIONINFO VersionInformation = + + { + sizeof(OSVERSIONINFO), + 0, + 0, + 0, + 0, + "", + }; + + if ( + GetVersionEx(&VersionInformation) && + (VersionInformation.dwPlatformId == VER_PLATFORM_WIN32_NT) + ) + { + isWNT = sal_True; + } + + isInit = sal_True; + } + + return(isWNT); +} + +static BOOL Privilege(LPTSTR strPrivilege, BOOL bEnable) +{ + HANDLE hToken; + TOKEN_PRIVILEGES tp; + + /* + obtain the processes token + */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_DUP_QUERY, &hToken)) + return FALSE; + + /* + get the luid + */ + if (!LookupPrivilegeValue(NULL, strPrivilege, &tp.Privileges[0].Luid)) + return FALSE; + + tp.PrivilegeCount = 1; + + if (bEnable) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + /* + enable or disable the privilege + */ + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0)) + return FALSE; + + if (!CloseHandle(hToken)) + return FALSE; + + return TRUE; +} + +static sal_Bool SAL_CALL getUserNameImpl(oslSecurity Security, rtl_uString **strName, sal_Bool bIncludeDomain) +{ + if (Security != NULL) + { + oslSecurityImpl *pSecImpl = (oslSecurityImpl*)Security; + + HANDLE hAccessToken = pSecImpl->m_hToken; + + if (hAccessToken == NULL) + OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY, &hAccessToken); + + if (hAccessToken) + { + DWORD nInfoBuffer = 512; + UCHAR* pInfoBuffer = malloc(nInfoBuffer); + + while (!GetTokenInformation(hAccessToken, TokenUser, + pInfoBuffer, nInfoBuffer, &nInfoBuffer)) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + pInfoBuffer = realloc(pInfoBuffer, nInfoBuffer); + else + { + free(pInfoBuffer); + pInfoBuffer = NULL; + break; + } + } + + if (pSecImpl->m_hToken == NULL) + CloseHandle(hAccessToken); + + if (pInfoBuffer) + { + sal_Unicode UserName[128]; + sal_Unicode DomainName[128]; + sal_Unicode Name[257]; + DWORD nUserName = sizeof(UserName); + DWORD nDomainName = sizeof(DomainName); + SID_NAME_USE sUse; + + if (LookupAccountSidW(NULL, ((PTOKEN_USER)pInfoBuffer)->User.Sid, + UserName, &nUserName, + DomainName, &nDomainName, &sUse)) + { + if (bIncludeDomain) + { + wcscpy(Name, DomainName); + wcscat(Name, L"/"); + wcscat(Name, UserName); + } + else + { + wcscpy(Name, UserName); + } + } + rtl_uString_newFromStr( strName, Name); + + free(pInfoBuffer); + + return (sal_True); + } + } + else + { + DWORD needed=0; + sal_Unicode *pNameW=NULL; + + WNetGetUserW(NULL, NULL, &needed); + pNameW = malloc (needed*sizeof(sal_Unicode)); + + if (WNetGetUserW(NULL, pNameW, &needed) == NO_ERROR) + { + rtl_uString_newFromStr( strName, pNameW); + + if (pNameW) + free(pNameW); + return (sal_True); + } + else + if (wcslen(pSecImpl->m_User) > 0) + { + rtl_uString_newFromStr( strName, pSecImpl->m_pNetResource->lpRemoteName); + + if (pNameW) + free(pNameW); + + return (sal_True); + } + + if (pNameW) + free(pNameW); + } + } + + return sal_False; +} + diff --git a/sal/osl/w32/semaphor.c b/sal/osl/w32/semaphor.c new file mode 100644 index 000000000000..e16a73d998fa --- /dev/null +++ b/sal/osl/w32/semaphor.c @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/semaphor.h> + +/* + Implemetation notes: + The void* represented by oslSemaphore is used + to store a WIN32 HANDLE. +*/ + + +/*****************************************************************************/ +/* osl_createSemaphore */ +/*****************************************************************************/ +oslSemaphore SAL_CALL osl_createSemaphore(sal_uInt32 initialCount) +{ + oslSemaphore Semaphore; + + Semaphore= CreateSemaphore(0, initialCount, INT_MAX, 0); + + /* create failed? */ + if((HANDLE)Semaphore == INVALID_HANDLE_VALUE) + { + Semaphore= 0; + } + + return Semaphore; +} + +/*****************************************************************************/ +/* osl_destroySemaphore */ +/*****************************************************************************/ +void SAL_CALL osl_destroySemaphore(oslSemaphore Semaphore) +{ + + + if(Semaphore != 0) + { + CloseHandle((HANDLE)Semaphore); + } + +} + +/*****************************************************************************/ +/* osl_acquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireSemaphore(oslSemaphore Semaphore) +{ + OSL_ASSERT(Semaphore != 0); + + switch ( WaitForSingleObject( (HANDLE)Semaphore, INFINITE ) ) + { + case WAIT_OBJECT_0: + return sal_True; + + default: + return (sal_False); + } +} + +/*****************************************************************************/ +/* osl_tryToAcquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireSemaphore(oslSemaphore Semaphore) +{ + OSL_ASSERT(Semaphore != 0); + return (sal_Bool)(WaitForSingleObject((HANDLE)Semaphore, 0) == WAIT_OBJECT_0); +} + + +/*****************************************************************************/ +/* osl_releaseSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseSemaphore(oslSemaphore Semaphore) +{ + OSL_ASSERT(Semaphore != 0); + + /* increase count by one, not interested in previous count */ + return (sal_Bool)(ReleaseSemaphore((HANDLE)Semaphore, 1, NULL) != FALSE); +} + + + diff --git a/sal/osl/w32/signal.cxx b/sal/osl/w32/signal.cxx new file mode 100644 index 000000000000..f893f7520d40 --- /dev/null +++ b/sal/osl/w32/signal.cxx @@ -0,0 +1,436 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2010 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +/* system headers */ +#include "system.h" +#include <tchar.h> + +#include "file_url.h" +#include "path_helper.hxx" + +#include <osl/diagnose.h> +#include <osl/mutex.h> +#include <osl/signal.h> +#ifndef __MINGW32__ +#include <DbgHelp.h> +#endif +#include <ErrorRep.h> +#include <systools/win32/uwinapi.h> + +typedef struct _oslSignalHandlerImpl +{ + oslSignalHandlerFunction Handler; + void* pData; + struct _oslSignalHandlerImpl* pNext; +} oslSignalHandlerImpl; + +static sal_Bool bErrorReportingEnabled = sal_True; +static sal_Bool bInitSignal = sal_False; +static oslMutex SignalListMutex; +static oslSignalHandlerImpl* SignalList; + +static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP); + +static sal_Bool InitSignal(void) +{ + HMODULE hFaultRep; + + SignalListMutex = osl_createMutex(); + + SetUnhandledExceptionFilter(SignalHandlerFunction); + + hFaultRep = LoadLibrary( "faultrep.dll" ); + if ( hFaultRep ) + { +#ifdef __MINGW32__ +typedef BOOL (WINAPI *pfn_ADDEREXCLUDEDAPPLICATIONW)(LPCWSTR); +#endif + pfn_ADDEREXCLUDEDAPPLICATIONW pfn = (pfn_ADDEREXCLUDEDAPPLICATIONW)GetProcAddress( hFaultRep, "AddERExcludedApplicationW" ); + if ( pfn ) + pfn( L"SOFFICE.EXE" ); + FreeLibrary( hFaultRep ); + } + + return sal_True; +} + +static sal_Bool DeInitSignal(void) +{ + SetUnhandledExceptionFilter(NULL); + + osl_destroyMutex(SignalListMutex); + + return sal_False; +} + +static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) +{ + oslSignalHandlerImpl* pHandler = SignalList; + oslSignalAction Action = osl_Signal_ActCallNextHdl; + + while (pHandler != NULL) + { + if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl) + break; + + pHandler = pHandler->pNext; + } + + return Action; +} + +/*****************************************************************************/ +/* SignalHandlerFunction */ +/*****************************************************************************/ + +#define REPORTENV_PARAM "-crashreportenv:" +#define REPORTENV_PARAM2 "/crashreportenv:" + +static BOOL ReportCrash( LPEXCEPTION_POINTERS lpEP ) +{ + BOOL fSuccess = FALSE; + BOOL fAutoReport = FALSE; + TCHAR szBuffer[1024]; + ::osl::LongPathBuffer< sal_Char > aPath( MAX_LONG_PATH ); + LPTSTR lpFilePart; + PROCESS_INFORMATION ProcessInfo; + STARTUPINFO StartupInfo; + int argi; + + if ( !bErrorReportingEnabled ) + return FALSE; + + /* Check if crash reporter was disabled by command line */ + + for ( argi = 1; argi < __argc; argi++ ) + { + if ( + 0 == stricmp( __argv[argi], "-nocrashreport" ) || + 0 == stricmp( __argv[argi], "/nocrashreport" ) + ) + return FALSE; + else if ( + 0 == stricmp( __argv[argi], "-autocrashreport" ) || + 0 == stricmp( __argv[argi], "/autocrashreport" ) + ) + fAutoReport = TRUE; + else if ( + 0 == strnicmp( __argv[argi], REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) || + 0 == strnicmp( __argv[argi], REPORTENV_PARAM2, strlen(REPORTENV_PARAM2) ) + ) + { + const char *envparam = __argv[argi] + strlen(REPORTENV_PARAM); + const char *delim = strchr(envparam, '=' ); + + if ( delim ) + { + CHAR *lpVariable; + CHAR *lpValue; + const char *variable = envparam; + size_t variable_len = delim - envparam; + const char *value = delim + 1; + size_t value_len = strlen(envparam) - variable_len - 1; + + if ( '\"' == *value ) + { + const char *quote; + + value++; + value_len--; + + quote = strchr( value, '\"' ); + if ( quote ) + value_len = quote - value; + } + + lpVariable = reinterpret_cast< CHAR* >( _alloca( variable_len + 1 ) ); + memcpy( lpVariable, variable, variable_len ); + lpVariable[variable_len] = 0; + + lpValue = reinterpret_cast< CHAR* >( _alloca( value_len + 1) ); + memcpy( lpValue, value, value_len ); + lpValue[value_len] = 0; + + SetEnvironmentVariable( lpVariable, lpValue ); + } + } + } + + if ( SearchPath( NULL, TEXT( "crashrep.exe" ), NULL, aPath.getBufSizeInSymbols(), aPath, &lpFilePart ) ) + { + ZeroMemory( &StartupInfo, sizeof(StartupInfo) ); + StartupInfo.cb = sizeof(StartupInfo.cb); + + + sntprintf( szBuffer, elementsof(szBuffer), + _T("%s -p %u -excp 0x%p -t %u%s"), + aPath, + GetCurrentProcessId(), + lpEP, + GetCurrentThreadId(), + fAutoReport ? _T(" -noui -send") : _T(" -noui") ); + + if ( + CreateProcess( + NULL, + szBuffer, + NULL, + NULL, + FALSE, +#ifdef UNICODE + CREATE_UNICODE_ENVIRONMENT, +#else + 0, +#endif + NULL, NULL, &StartupInfo, &ProcessInfo ) + ) + { + DWORD dwExitCode; + + WaitForSingleObject( ProcessInfo.hProcess, INFINITE ); + if ( GetExitCodeProcess( ProcessInfo.hProcess, &dwExitCode ) && 0 == dwExitCode ) + + fSuccess = TRUE; + + } + } + + return fSuccess; +} + +/*****************************************************************************/ +/* SignalHandlerFunction */ +/*****************************************************************************/ + +static BOOL WINAPI IsWin95A(void) +{ + OSVERSIONINFO ovi; + + ZeroMemory( &ovi, sizeof(ovi) ); + ovi.dwOSVersionInfoSize = sizeof(ovi); + + if ( GetVersionEx( &ovi ) ) + /* See MSDN January 2000 documentation of GetVersionEx */ + return (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && + (ovi.dwMajorVersion <= 4) && + (ovi.dwMinorVersion == 0) && + (ovi.dwBuildNumber == 0x040003B6); + + /* Something wrent wrong. So assume we have an older operating prior Win95 */ + + return TRUE; +} + +/* magic Microsoft C++ compiler exception constant */ +#define EXCEPTION_MSC_CPP_EXCEPTION 0xe06d7363 + +static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP) +{ + static sal_Bool bNested = sal_False; + sal_Bool bRaiseCrashReporter = sal_False; + oslSignalInfo Info; + oslSignalAction Action; + + Info.UserSignal = lpEP->ExceptionRecord->ExceptionCode; + Info.UserData = NULL; + + switch (lpEP->ExceptionRecord->ExceptionCode) + { + /* Transform unhandled exceptions into access violations. + Microsoft C++ compiler (add more for other compilers if necessary). + */ + case EXCEPTION_MSC_CPP_EXCEPTION: + case EXCEPTION_ACCESS_VIOLATION: + Info.Signal = osl_Signal_AccessViolation; + bRaiseCrashReporter = sal_True; + break; + + case EXCEPTION_INT_DIVIDE_BY_ZERO: + Info.Signal = osl_Signal_IntegerDivideByZero; + bRaiseCrashReporter = sal_True; + break; + + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + Info.Signal = osl_Signal_FloatDivideByZero; + bRaiseCrashReporter = sal_True; + break; + + case EXCEPTION_BREAKPOINT: + Info.Signal = osl_Signal_DebugBreak; + break; + + default: + Info.Signal = osl_Signal_System; + bRaiseCrashReporter = sal_True; + break; + } + + if ( !bNested ) + { + bNested = sal_True; + + if ( bRaiseCrashReporter && ReportCrash( lpEP ) || IsWin95A() ) + { + CallSignalHandler(&Info); + Action = osl_Signal_ActKillApp; + } + else + Action = CallSignalHandler(&Info); + } + else + Action = osl_Signal_ActKillApp; + + + switch ( Action ) + { + case osl_Signal_ActCallNextHdl: + return (EXCEPTION_CONTINUE_SEARCH); + + case osl_Signal_ActAbortApp: + return (EXCEPTION_EXECUTE_HANDLER); + + case osl_Signal_ActKillApp: + SetErrorMode(SEM_NOGPFAULTERRORBOX); + exit(255); + break; + default: + break; + } + + return (EXCEPTION_CONTINUE_EXECUTION); +} + +/*****************************************************************************/ +/* osl_addSignalHandler */ +/*****************************************************************************/ +oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) +{ + oslSignalHandlerImpl* pHandler; + + OSL_ASSERT(Handler != NULL); + + if (! bInitSignal) + bInitSignal = InitSignal(); + + pHandler = reinterpret_cast< oslSignalHandlerImpl* >( calloc( 1, sizeof(oslSignalHandlerImpl) ) ); + + if (pHandler != NULL) + { + pHandler->Handler = Handler; + pHandler->pData = pData; + + osl_acquireMutex(SignalListMutex); + + pHandler->pNext = SignalList; + SignalList = pHandler; + + osl_releaseMutex(SignalListMutex); + + return (pHandler); + } + + return (NULL); +} + +/*****************************************************************************/ +/* osl_removeSignalHandler */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) +{ + oslSignalHandlerImpl *pHandler, *pPrevious = NULL; + + OSL_ASSERT(Handler != NULL); + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + pHandler = SignalList; + + while (pHandler != NULL) + { + if (pHandler == Handler) + { + if (pPrevious) + pPrevious->pNext = pHandler->pNext; + else + SignalList = pHandler->pNext; + + osl_releaseMutex(SignalListMutex); + + if (SignalList == NULL) + bInitSignal = DeInitSignal(); + + free(pHandler); + + return (sal_True); + } + + pPrevious = pHandler; + pHandler = pHandler->pNext; + } + + osl_releaseMutex(SignalListMutex); + + return (sal_False); +} + +/*****************************************************************************/ +/* osl_raiseSignal */ +/*****************************************************************************/ +oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) +{ + oslSignalInfo Info; + oslSignalAction Action; + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + Info.Signal = osl_Signal_User; + Info.UserSignal = UserSignal; + Info.UserData = UserData; + + Action = CallSignalHandler(&Info); + + osl_releaseMutex(SignalListMutex); + + return (Action); +} + +/*****************************************************************************/ +/* osl_setErrorReporting */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) +{ + sal_Bool bOld = bErrorReportingEnabled; + bErrorReportingEnabled = bEnable; + + return bOld; +} diff --git a/sal/osl/w32/socket.cxx b/sal/osl/w32/socket.cxx new file mode 100644 index 000000000000..191c31fb986a --- /dev/null +++ b/sal/osl/w32/socket.cxx @@ -0,0 +1,2190 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "system.h" + +#include <osl/socket.h> +#include <osl/diagnose.h> +#include <rtl/alloc.h> + +#include "sockimpl.h" + +extern "C" { + +/* defines for shutdown */ +#ifdef GCC +# define SD_RECEIVE 0 +# define SD_SEND 1 +# define SD_BOTH 2 +#endif + +/* + oslSocketAddr is a pointer to a Berkeley struct sockaddr. + I refrained from using sockaddr_in because of possible further + extensions of this socket-interface (IP-NG?). + The intention was to hide all Berkeley data-structures from + direct access past the osl-interface. + + The current implementation is internet (IP) centered. All + the constructor-functions (osl_create...) take parameters + that will probably make sense only in the IP-environment + (e.g. because of using the dotted-Addr-format). + + If the interface will be extended to host other protocol- + families, I expect no externally visible changes in the + existing functions. You'll probably need only new + constructor-functions who take the different Addr + formats into consideration (maybe a long dotted Addr + or whatever). +*/ + +/* + _Note_ that I rely on the fact that oslSocketAddr and struct sockaddr + are the same! I don't like it very much but see no other easy way to + conceal the struct sockaddr from the eyes of the user. +*/ + +#define OSL_INVALID_SOCKET INVALID_SOCKET /* WIN32 */ +#define OSL_SOCKET_ERROR SOCKET_ERROR /* WIN32 */ + +/*****************************************************************************/ +/* enum oslAddrFamily */ +/*****************************************************************************/ + +/* map */ +static DWORD FamilyMap[]= { + AF_INET, /* osl_Socket_FamilyInet */ + AF_IPX, /* osl_Socket_FamilyIpx */ + 0 /* osl_Socket_FamilyInvalid */ +}; + +/* reverse map */ +static oslAddrFamily osl_AddrFamilyFromNative(DWORD nativeType) +{ + oslAddrFamily i= (oslAddrFamily) 0; + while(i != osl_Socket_FamilyInvalid) + { + if(FamilyMap[i] == nativeType) + return i; + i = (oslAddrFamily) ( (int)i + 1); + } + return i; +} + +/* macros */ +#define FAMILY_FROM_NATIVE(y) osl_AddrFamilyFromNative(y) +#define FAMILY_TO_NATIVE(x) (short)FamilyMap[x] + +/*****************************************************************************/ +/* enum oslProtocol */ +/*****************************************************************************/ + +/* map */ +static DWORD ProtocolMap[]= { + 0, /* osl_Socket_FamilyInet */ + NSPROTO_IPX, /* osl_Socket_FamilyIpx */ + NSPROTO_SPX, /* osl_Socket_ProtocolSpx */ + NSPROTO_SPXII, /* osl_Socket_ProtocolSpx_ii */ + 0 /* osl_Socket_ProtocolInvalid */ +}; + +/* macros */ +#define PROTOCOL_FROM_NATIVE(y) osl_ProtocolFromNative(y) +#define PROTOCOL_TO_NATIVE(x) ProtocolMap[x] + +/*****************************************************************************/ +/* enum oslSocketType */ +/*****************************************************************************/ + +/* map */ +static DWORD TypeMap[]= { + SOCK_STREAM, /* osl_Socket_TypeStream */ + SOCK_DGRAM, /* osl_Socket_TypeDgram */ + SOCK_RAW, /* osl_Socket_TypeRaw */ + SOCK_RDM, /* osl_Socket_TypeRdm */ + SOCK_SEQPACKET, /* osl_Socket_TypeSeqPacket */ + 0 /* osl_Socket_TypeInvalid */ +}; + +/* reverse map */ +static oslSocketType osl_SocketTypeFromNative(DWORD nativeType) +{ + oslSocketType i= (oslSocketType)0; + while(i != osl_Socket_TypeInvalid) + { + if(TypeMap[i] == nativeType) + return i; + i = (oslSocketType)((int)i+1); + } + return i; +} + +/* macros */ +#define TYPE_TO_NATIVE(x) TypeMap[x] +#define TYPE_FROM_NATIVE(y) osl_SocketTypeFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketOption */ +/*****************************************************************************/ + +/* map */ +static DWORD OptionMap[]= { + SO_DEBUG, /* osl_Socket_OptionDebug */ + SO_ACCEPTCONN, /* osl_Socket_OptionAcceptConn */ + SO_REUSEADDR, /* osl_Socket_OptionReuseAddr */ + SO_KEEPALIVE, /* osl_Socket_OptionKeepAlive */ + SO_DONTROUTE, /* osl_Socket_OptionDontRoute */ + SO_BROADCAST, /* osl_Socket_OptionBroadcast */ + SO_USELOOPBACK, /* osl_Socket_OptionUseLoopback */ + SO_LINGER, /* osl_Socket_OptionLinger */ + SO_OOBINLINE, /* osl_Socket_OptionOOBinLine */ + SO_SNDBUF, /* osl_Socket_OptionSndBuf */ + SO_RCVBUF, /* osl_Socket_OptionRcvBuf */ + SO_SNDLOWAT, /* osl_Socket_OptionSndLowat */ + SO_RCVLOWAT, /* osl_Socket_OptionRcvLowat */ + SO_SNDTIMEO, /* osl_Socket_OptionSndTimeo */ + SO_RCVTIMEO, /* osl_Socket_OptionRcvTimeo */ + SO_ERROR, /* osl_Socket_OptionError */ + SO_TYPE, /* osl_Socket_OptionType */ + TCP_NODELAY, /* osl_Socket_OptionTcpNoDelay */ + 0 /* osl_Socket_OptionInvalid */ +}; + +/* macros */ +#define OPTION_TO_NATIVE(x) OptionMap[x] +#define OPTION_FROM_NATIVE(y) osl_SocketOptionFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketOptionLevel */ +/*****************************************************************************/ + +static DWORD OptionLevelMap[]= { + SOL_SOCKET, /* osl_Socket_LevelSocket */ + IPPROTO_TCP, /* osl_Socket_LevelTcp */ + 0 /* osl_invalid_SocketLevel */ +}; + +/* macros */ +#define OPTION_LEVEL_TO_NATIVE(x) OptionLevelMap[x] +#define OPTION_LEVEL_FROM_NATIVE(y) osl_SocketOptionLevelFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketMsgFlag */ +/*****************************************************************************/ + +static DWORD SocketMsgFlagMap[]= { + 0, /* osl_Socket_MsgNormal */ + MSG_OOB, /* osl_Socket_MsgOOB */ + MSG_PEEK, /* osl_Socket_MsgPeek */ + MSG_DONTROUTE, /* osl_Socket_MsgDontRoute */ + MSG_MAXIOVLEN /* osl_Socket_MsgMaxIOVLen */ +}; + +/* macros */ +#define MSG_FLAG_TO_NATIVE(x) SocketMsgFlagMap[x] +#define MSG_FLAG_FROM_NATIVE(y) osl_SocketMsgFlagFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketDirection */ +/*****************************************************************************/ + +static DWORD SocketDirection[]= { + SD_RECEIVE, /* osl_Socket_DirRead */ + SD_SEND, /* osl_Socket_DirWrite */ + SD_BOTH /* osl_Socket_DirReadwrite */ +}; + +/* macros */ +#define DIRECTION_TO_NATIVE(x) SocketDirection[x] +#define DIRECTION_FROM_NATIVE(y) osl_SocketDirectionFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketError */ +/*****************************************************************************/ + +static int SocketError[]= { + + 0, /* no error */ + WSAENOTSOCK, /* Socket operation on non-socket */ + WSAEDESTADDRREQ, /* Destination address required */ + WSAEMSGSIZE, /* Message too long */ + WSAEPROTOTYPE, /* Protocol wrong type for socket */ + WSAENOPROTOOPT, /* Protocol not available */ + WSAEPROTONOSUPPORT, /* Protocol not supported */ + WSAESOCKTNOSUPPORT, /* Socket type not supported */ + WSAEOPNOTSUPP, /* Operation not supported on socket */ + WSAEPFNOSUPPORT, /* Protocol family not supported */ + WSAEAFNOSUPPORT, /* Address family not supported by */ + /* protocol family */ + WSAEADDRINUSE, /* Address already in use */ + WSAEADDRNOTAVAIL, /* Can't assign requested address */ + WSAENETDOWN, /* Network is down */ + WSAENETUNREACH, /* Network is unreachable */ + WSAENETRESET, /* Network dropped connection because */ + /* of reset */ + WSAECONNABORTED, /* Software caused connection abort */ + WSAECONNRESET, /* Connection reset by peer */ + WSAENOBUFS, /* No buffer space available */ + WSAEISCONN, /* Socket is already connected */ + WSAENOTCONN, /* Socket is not connected */ + WSAESHUTDOWN, /* Can't send after socket shutdown */ + WSAETOOMANYREFS, /* Too many references: can't splice */ + WSAETIMEDOUT, /* Connection timed out */ + WSAECONNREFUSED, /* Connection refused */ + WSAEHOSTDOWN, /* Host is down */ + WSAEHOSTUNREACH, /* No route to host */ + WSAEWOULDBLOCK, /* call would block on non-blocking socket */ + WSAEALREADY, /* operation already in progress */ + WSAEINPROGRESS /* operation now in progress */ +}; + +/* reverse map */ +static oslSocketError osl_SocketErrorFromNative(int nativeType) +{ + oslSocketError i= (oslSocketError)0; + + while(i != osl_Socket_E_InvalidError) + { + if(SocketError[i] == nativeType) + return i; + + i = (oslSocketError)( (int) i + 1); + } + return i; +} + +/* macros */ +#define ERROR_TO_NATIVE(x) SocketError[x] +#define ERROR_FROM_NATIVE(y) osl_SocketErrorFromNative(y) + +/*****************************************************************************/ +/* oslSocketDialupImpl */ +/*****************************************************************************/ +static oslSocketDialupImpl *pDialupImpl = NULL; + +#if 0 /* INTERNAL DEBUG ONLY */ +BOOL WINAPI __osl_autodial_Impl (DWORD dwFlags, DWORD dwReserved) +{ + return 0; +} + +BOOL WINAPI __osl_autodialHangup_Impl (DWORD dwReserved) +{ + return 1; +} + +BOOL WINAPI __osl_getConnectedState_Impl (LPDWORD lpdwFlags, DWORD dwReserved) +{ + if (lpdwFlags) + *lpdwFlags = 0; + return 0; +} +#endif /* INTERNAL DEBUG ONLY */ + +/* + * __osl_createSocketDialupImpl. + */ +static oslSocketDialupImpl* __osl_createSocketDialupImpl (void) +{ + oslSocketDialupImpl *pImpl; + pImpl = (oslSocketDialupImpl*)rtl_allocateZeroMemory( sizeof (oslSocketDialupImpl)); + + InitializeCriticalSection (&pImpl->m_hMutex); + + return (pImpl); +} + +/* + * __osl_initSocketDialupImpl. + */ +static void __osl_initSocketDialupImpl (oslSocketDialupImpl *pImpl) +{ +#ifdef SOCKET_USE_AUTODIAL + if (pImpl) + { + HINSTANCE hModule; + + EnterCriticalSection (&pImpl->m_hMutex); + + hModule = LoadLibrary (INTERNET_MODULE_NAME); + if (!(hModule <= (HINSTANCE)HINSTANCE_ERROR)) + { + pImpl->m_pfnAttemptConnect = (INTERNETATTEMPTCONNECT) + (GetProcAddress (hModule, "InternetAttemptConnect")); + pImpl->m_pfnAutodial = (INTERNETAUTODIAL) + (GetProcAddress (hModule, "InternetAutodial")); + pImpl->m_pfnAutodialHangup = (INTERNETAUTODIALHANGUP) + (GetProcAddress (hModule, "InternetAutodialHangup")); + pImpl->m_pfnGetConnectedState = (INTERNETGETCONNECTEDSTATE) + (GetProcAddress (hModule, "InternetGetConnectedState")); + pImpl->m_hModule = hModule; + } + + LeaveCriticalSection (&pImpl->m_hMutex); + } +#else + pImpl = pImpl; /* avoid warnings */ +#endif +} + +/* + * __osl_destroySocketDialupImpl. + */ +static void __osl_destroySocketDialupImpl (oslSocketDialupImpl *pImpl) +{ + if (pImpl) + { + EnterCriticalSection (&pImpl->m_hMutex); + + if (pImpl->m_dwFlags & INTERNET_CONNECTION_HANGUP) + { + if (pImpl->m_pfnAutodialHangup) + { + (pImpl->m_pfnAutodialHangup)(0); + pImpl->m_dwFlags &= ~INTERNET_CONNECTION_HANGUP; + } + } + + if (pImpl->m_hModule) + FreeLibrary (pImpl->m_hModule); + + LeaveCriticalSection (&pImpl->m_hMutex); + DeleteCriticalSection (&pImpl->m_hMutex); + + rtl_freeMemory (pImpl); + } +} + +/* + * __osl_querySocketDialupImpl. + */ +static sal_Bool __osl_querySocketDialupImpl (void) +{ + sal_Bool result; + + if (pDialupImpl == NULL) + { + pDialupImpl = __osl_createSocketDialupImpl(); + __osl_initSocketDialupImpl (pDialupImpl); + } + + EnterCriticalSection (&pDialupImpl->m_hMutex); + + result = sal_True; + if (pDialupImpl->m_pfnGetConnectedState) + { + DWORD dwFlags = 0; + + result = (sal_Bool)(pDialupImpl->m_pfnGetConnectedState)(&dwFlags, 0); + pDialupImpl->m_dwFlags |= dwFlags; + } + + LeaveCriticalSection (&pDialupImpl->m_hMutex); + return (result); +} + +/* + * __osl_attemptSocketDialupImpl. + */ +static sal_Bool __osl_attemptSocketDialupImpl (void) +{ + sal_Bool result; + + if (pDialupImpl == NULL) + { + pDialupImpl = __osl_createSocketDialupImpl(); + __osl_initSocketDialupImpl (pDialupImpl); + } + + EnterCriticalSection (&pDialupImpl->m_hMutex); + + result = __osl_querySocketDialupImpl(); + if (!result) + { + result = sal_True; + if (pDialupImpl->m_pfnAutodial) + { + result = (sal_Bool)(pDialupImpl->m_pfnAutodial)(0, 0); + if (result) + pDialupImpl->m_dwFlags |= INTERNET_CONNECTION_HANGUP; + else + WSASetLastError (WSAENETDOWN); + } + } + + LeaveCriticalSection (&pDialupImpl->m_hMutex); + return (result); +} + +/*****************************************************************************/ +/* oslSocketImpl */ +/*****************************************************************************/ +static sal_uInt32 g_nSocketImpl = 0; + +#if OSL_DEBUG_LEVEL > 1 +static sal_uInt32 g_nSocketAddr = 0; +struct LeakWarning +{ + ~LeakWarning() + { + if( g_nSocketImpl ) + OSL_TRACE( "sal_socket: %d socket instances leak\n" , g_nSocketImpl ); + if( g_nSocketAddr ) + OSL_TRACE( "sal_socket: %d socket address instances leak\n" , g_nSocketAddr ); + } +}; +LeakWarning socketWarning; +#endif + +/* + * __osl_createSocketImpl. + */ +oslSocket __osl_createSocketImpl(SOCKET Socket) +{ + oslSocket pSockImpl = (oslSocket) rtl_allocateZeroMemory( sizeof(struct oslSocketImpl)); + pSockImpl->m_Socket = Socket; + pSockImpl->m_nRefCount = 1; + + g_nSocketImpl++; + + return (pSockImpl); +} + +/* + * __osl_destroySocketImpl. + */ +void __osl_destroySocketImpl(oslSocketImpl *pImpl) +{ + if (pImpl) + { + if (--g_nSocketImpl == 0) + { + __osl_destroySocketDialupImpl (pDialupImpl); + pDialupImpl = NULL; + } + rtl_freeMemory (pImpl); + } +} +/*****************************************************************************/ +static oslSocketAddr __osl_createSocketAddr( ) +{ + oslSocketAddr pAddr = (oslSocketAddr) rtl_allocateZeroMemory( sizeof( struct oslSocketAddrImpl )); + pAddr->m_nRefCount = 1; +#if OSL_DEBUG_LEVEL > 1 + g_nSocketAddr ++; +#endif + return pAddr; +} + +static oslSocketAddr __osl_createSocketAddrWithFamily( + oslAddrFamily family, sal_Int32 port, sal_uInt32 nAddr ) +{ + OSL_ASSERT( family == osl_Socket_FamilyInet ); + + oslSocketAddr pAddr = __osl_createSocketAddr(); + switch( family ) + { + case osl_Socket_FamilyInet: + { + struct sockaddr_in* pInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + pInetAddr->sin_family = FAMILY_TO_NATIVE(osl_Socket_FamilyInet); + pInetAddr->sin_addr.s_addr = nAddr; + pInetAddr->sin_port = (sal_uInt16)(port&0xffff); + break; + } + default: + pAddr->m_sockaddr.sa_family = FAMILY_TO_NATIVE(family); + } + return pAddr; +} + +static oslSocketAddr __osl_createSocketAddrFromSystem( struct sockaddr *pSystemSockAddr ) +{ + oslSocketAddr pAddr = __osl_createSocketAddr(); + memcpy( &(pAddr->m_sockaddr), pSystemSockAddr, sizeof( sockaddr ) ); + return pAddr; +} + +static void __osl_destroySocketAddr( oslSocketAddr addr ) +{ +#if OSL_DEBUG_LEVEL > 1 + g_nSocketAddr --; +#endif + rtl_freeMemory( addr ); +} +/*****************************************************************************/ +/* osl_createEmptySocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createEmptySocketAddr(oslAddrFamily Family) +{ + oslSocketAddr pAddr = 0; + + /* is it an internet-Addr? */ + if (Family == osl_Socket_FamilyInet) + { + pAddr = __osl_createSocketAddrWithFamily(Family, 0 , htonl(INADDR_ANY) ); + } + else + { + pAddr = __osl_createSocketAddrWithFamily( Family , 0 , 0 ); + } + + return pAddr; +} + +/*****************************************************************************/ +/* osl_copySocketAddr */ +/*****************************************************************************/ +// @deprecated, to be removed +oslSocketAddr SAL_CALL osl_copySocketAddr(oslSocketAddr Addr) +{ + oslSocketAddr pCopy = 0; + if (Addr) + { + pCopy = __osl_createSocketAddr(); + + if (pCopy) + memcpy(&(pCopy->m_sockaddr),&(Addr->m_sockaddr), sizeof(struct sockaddr)); + } + return pCopy; +} + +/*****************************************************************************/ +/* osl_isEqualSocketAddr */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isEqualSocketAddr(oslSocketAddr Addr1, oslSocketAddr Addr2) +{ + struct sockaddr* pAddr1= &(Addr1->m_sockaddr); + struct sockaddr* pAddr2= &(Addr2->m_sockaddr); + + OSL_ASSERT(pAddr1); + OSL_ASSERT(pAddr2); + + if (pAddr1->sa_family == pAddr2->sa_family) + { + switch (pAddr1->sa_family) + { + case AF_INET: + { + struct sockaddr_in* pInetAddr1= (struct sockaddr_in*)pAddr1; + struct sockaddr_in* pInetAddr2= (struct sockaddr_in*)pAddr2; + + if ((pInetAddr1->sin_family == pInetAddr2->sin_family) && + (pInetAddr1->sin_addr.s_addr == pInetAddr2->sin_addr.s_addr) && + (pInetAddr1->sin_port == pInetAddr2->sin_port)) + return (sal_True); + } + + default: + { + return (memcmp(pAddr1, Addr2, sizeof(struct sockaddr)) == 0); + } + } + } + + return (sal_False); +} + +/*****************************************************************************/ +/* osl_createInetBroadcastAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createInetBroadcastAddr ( + rtl_uString *strDottedAddr, + sal_Int32 Port) +{ + sal_uInt32 nAddr = OSL_INADDR_NONE; + + if (strDottedAddr && strDottedAddr->length) + { + /* Dotted host address for limited broadcast */ + rtl_String *pDottedAddr = NULL; + + rtl_uString2String ( + &pDottedAddr, strDottedAddr->buffer, strDottedAddr->length, + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + + nAddr = inet_addr (pDottedAddr->buffer); + rtl_string_release (pDottedAddr); + } + + if (nAddr != OSL_INADDR_NONE) + { + /* Limited broadcast */ + nAddr = ntohl(nAddr); + if (IN_CLASSA(nAddr)) + { + nAddr &= IN_CLASSA_NET; + nAddr |= IN_CLASSA_HOST; + } + else if (IN_CLASSB(nAddr)) + { + nAddr &= IN_CLASSB_NET; + nAddr |= IN_CLASSB_HOST; + } + else if (IN_CLASSC(nAddr)) + { + nAddr &= IN_CLASSC_NET; + nAddr |= IN_CLASSC_HOST; + } + else + { + /* No broadcast in class D */ + return ((oslSocketAddr)NULL); + } + nAddr = htonl(nAddr); + } + + oslSocketAddr pAddr = + __osl_createSocketAddrWithFamily( osl_Socket_FamilyInet, htons( (sal_uInt16) Port), nAddr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_createInetSocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createInetSocketAddr ( + rtl_uString *strDottedAddr, + sal_Int32 Port) +{ + DWORD Addr; + rtl_String *pDottedAddr=NULL; + + rtl_uString2String( + &pDottedAddr, strDottedAddr->buffer, strDottedAddr->length, + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + + Addr= inet_addr (pDottedAddr->buffer); + rtl_string_release (pDottedAddr); + + oslSocketAddr pAddr = 0; + if(Addr != -1) + { + pAddr = __osl_createSocketAddrWithFamily( osl_Socket_FamilyInet, htons( (sal_uInt16)Port), Addr ); + } + return pAddr; +} + +oslSocketResult SAL_CALL osl_setAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence *pByteSeq ) +{ + OSL_ASSERT( pAddr ); + OSL_ASSERT( pByteSeq ); + + oslSocketResult res = osl_Socket_Error; + if( pAddr && pByteSeq ) + { + OSL_ASSERT( pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE( osl_Socket_FamilyInet ) ); + OSL_ASSERT( pByteSeq->nElements == 4 ); + struct sockaddr_in * pSystemInetAddr = (struct sockaddr_in * ) &(pAddr->m_sockaddr); + memcpy( &(pSystemInetAddr->sin_addr) , pByteSeq->elements , 4 ); + res = osl_Socket_Ok; + } + return res; +} + +/** Returns the addr field in the struct sockaddr. ppByteSeq is in network byteorder. *ppByteSeq may + either be 0 or contain a constructed sal_Sequence. + */ +oslSocketResult SAL_CALL osl_getAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence **ppByteSeq ) +{ + OSL_ASSERT( pAddr ); + OSL_ASSERT( ppByteSeq ); + + oslSocketResult res = osl_Socket_Error; + if( pAddr && ppByteSeq ) + { + struct sockaddr_in * pSystemInetAddr = (struct sockaddr_in * ) &(pAddr->m_sockaddr); + rtl_byte_sequence_constructFromArray( ppByteSeq , (sal_Int8 *) &(pSystemInetAddr->sin_addr),4); + res = osl_Socket_Ok; + } + return res; +} + +/*****************************************************************************/ +/* oslHostAddr */ +/*****************************************************************************/ +struct oslHostAddrImpl { + rtl_uString *pHostName; + oslSocketAddr pSockAddr; +} ; + +static oslHostAddr __osl_hostentToHostAddr (const struct hostent *he) +{ + oslHostAddr pAddr= NULL; + oslSocketAddr pSocketAddr = 0; + + rtl_uString *cn= NULL; + + if ((he == NULL) || (he->h_name == NULL) || (he->h_addr_list[0] == NULL)) + return ((oslHostAddr)NULL); + + rtl_string2UString( + &cn, he->h_name, strlen(he->h_name), + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + OSL_ASSERT(cn != 0); + + pSocketAddr = __osl_createSocketAddr(); + + if (pSocketAddr == NULL) + { + rtl_uString_release(cn); + return ((oslHostAddr)NULL); + } + + pSocketAddr->m_sockaddr.sa_family = he->h_addrtype; + if (pSocketAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + struct sockaddr_in *sin= (struct sockaddr_in *)&(pSocketAddr->m_sockaddr); + memcpy ( + &(sin->sin_addr.s_addr), + he->h_addr_list[0], + he->h_length); + } + else + { + /* unknown address family */ + /* future extensions for new families might be implemented here */ + + OSL_TRACE("_osl_hostentToHostAddr(): unknown address family.\n"); + OSL_ASSERT(sal_False); + + __osl_destroySocketAddr( pSocketAddr ); + rtl_uString_release(cn); + return ((oslHostAddr)NULL); + } + + pAddr= (oslHostAddr )rtl_allocateMemory (sizeof (struct oslHostAddrImpl)); + + if (pAddr == NULL) + { + __osl_destroySocketAddr( pSocketAddr ); + rtl_uString_release(cn); + return ((oslHostAddr)NULL); + } + + pAddr->pHostName= cn; + pAddr->pSockAddr= pSocketAddr; + + return pAddr; +} + +/*****************************************************************************/ +/* osl_createHostAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddr ( + rtl_uString *strHostname, + const oslSocketAddr pSocketAddr) +{ + oslHostAddr pAddr; + rtl_uString *cn= NULL; + + if ((strHostname == NULL) || (strHostname->length == 0) || (pSocketAddr == NULL)) + return ((oslHostAddr)NULL); + + rtl_uString_newFromString( &cn, strHostname); + + if ( ! pSocketAddr ) + { + rtl_uString_release(cn); + return ((oslHostAddr)NULL); + } + + pAddr= (oslHostAddr)rtl_allocateMemory (sizeof (struct oslHostAddrImpl)); + + if (pAddr == NULL) + { + rtl_uString_release(cn); + return ((oslHostAddr)NULL); + } + + pAddr->pHostName= cn; + pAddr->pSockAddr= osl_copySocketAddr( pSocketAddr ); + + return ((oslHostAddr)pAddr); +} + +/*****************************************************************************/ +/* osl_createHostAddrByName */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddrByName(rtl_uString *strHostname) +{ + if ((strHostname == NULL) || (strHostname->length == 0)) + return ((oslHostAddr)NULL); + + if (__osl_attemptSocketDialupImpl()) + { + struct hostent *he; + rtl_String *Hostname= NULL; + + rtl_uString2String( + &Hostname, strHostname->buffer, strHostname->length, + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + + he= gethostbyname (Hostname->buffer); + + rtl_string_release (Hostname); + return __osl_hostentToHostAddr (he); + } + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_createHostAddrByAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddrByAddr(const oslSocketAddr pAddr) +{ + if (pAddr == NULL) + return ((oslHostAddr)NULL); + + if (pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + const struct sockaddr_in *sin= (const struct sockaddr_in *)&(pAddr->m_sockaddr); + + if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) + return ((oslHostAddr)NULL); + + if (__osl_attemptSocketDialupImpl()) + { + struct hostent *he; + he= gethostbyaddr ((const sal_Char *)&(sin->sin_addr), + sizeof (sin->sin_addr), + sin->sin_family); + return __osl_hostentToHostAddr (he); + } + } + + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_copyHostAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_copyHostAddr(const oslHostAddr Addr) +{ + oslHostAddr pAddr= (oslHostAddr)Addr; + + if (pAddr) + return osl_createHostAddr (pAddr->pHostName, pAddr->pSockAddr); + else + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_getHostnameOfHostAddr */ +/*****************************************************************************/ +void SAL_CALL osl_getHostnameOfHostAddr( + const oslHostAddr pAddr, rtl_uString **strHostname) +{ + if (pAddr) + rtl_uString_assign (strHostname, pAddr->pHostName); + else + rtl_uString_new (strHostname); +} + +/*****************************************************************************/ +/* osl_getSocketAddrOfHostAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getSocketAddrOfHostAddr(const oslHostAddr pAddr) +{ + if (pAddr) + return (const oslSocketAddr)(pAddr->pSockAddr); + else + return NULL; +} + +/*****************************************************************************/ +/* osl_destroyHostAddr */ +/*****************************************************************************/ +void SAL_CALL osl_destroyHostAddr(oslHostAddr pAddr) +{ + if (pAddr) + { + if (pAddr->pHostName) + rtl_uString_release (pAddr->pHostName); + if (pAddr->pSockAddr) + osl_destroySocketAddr( pAddr->pSockAddr ); + + rtl_freeMemory (pAddr); + } +} + +/*****************************************************************************/ +/* osl_getLocalHostname */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getLocalHostname (rtl_uString **strLocalHostname) +{ + static sal_Unicode LocalHostname[256] = {0}; + + if (rtl_ustr_getLength(LocalHostname) == 0) + { + sal_Char Host[256]= ""; + if (gethostname(Host, sizeof(Host)) == 0) + { + /* check if we have an FQDN */ + if (strchr(Host, '.') == NULL) + { + oslHostAddr pAddr; + rtl_uString *hostName= NULL; + + rtl_string2UString( + &hostName, Host, strlen(Host), + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + OSL_ASSERT(hostName != 0); + + /* no, determine it via dns */ + pAddr = osl_createHostAddrByName(hostName); + rtl_uString_release (hostName); + + if (pAddr && pAddr->pHostName) + memcpy(LocalHostname, pAddr->pHostName->buffer, sizeof(sal_Unicode)*(rtl_ustr_getLength(pAddr->pHostName->buffer)+1)); + else + memset(LocalHostname, 0, sizeof(LocalHostname)); + + osl_destroyHostAddr ((oslHostAddr)pAddr); + } + } + } + + if (rtl_ustr_getLength(LocalHostname) > 0) + { + rtl_uString_newFromStr (strLocalHostname, LocalHostname); + return osl_Socket_Ok; + } + + return osl_Socket_Error; +} + +/*****************************************************************************/ +/* osl_resolveHostname */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_resolveHostname(rtl_uString* strHostname) +{ + oslHostAddr pAddr= + (oslHostAddr )osl_createHostAddrByName (strHostname); + if (pAddr) + { + oslSocketAddr SockAddr = osl_copySocketAddr( pAddr->pSockAddr ); + osl_destroyHostAddr(pAddr); + return (SockAddr); + } + return ((oslSocketAddr)NULL); +} + +/*****************************************************************************/ +/* osl_getServicePort */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getServicePort ( + rtl_uString* strServicename, + rtl_uString* strProtocol) +{ + struct servent* ps; + + rtl_String *str_Servicename=NULL; + rtl_String *str_Protocol=NULL; + + rtl_uString2String( + &str_Servicename, + rtl_uString_getStr(strServicename), + rtl_uString_getLength(strServicename), + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + rtl_uString2String( + &str_Protocol, + rtl_uString_getStr(strProtocol), + rtl_uString_getLength(strProtocol), + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + + ps= getservbyname( + rtl_string_getStr(str_Servicename), + rtl_string_getStr(str_Protocol)); + + rtl_string_release( str_Servicename ); + rtl_string_release( str_Protocol ); + + if (ps != 0) + return ntohs(ps->s_port); + + return OSL_INVALID_PORT; +} + +/*****************************************************************************/ +/* osl_destroySocketAddr */ +/*****************************************************************************/ +void SAL_CALL osl_destroySocketAddr(oslSocketAddr pAddr) +{ + __osl_destroySocketAddr( pAddr ); +} + +/*****************************************************************************/ +/* osl_getFamilyOfSocketAddr */ +/*****************************************************************************/ +oslAddrFamily SAL_CALL osl_getFamilyOfSocketAddr(oslSocketAddr pAddr) +{ + if (pAddr) + return FAMILY_FROM_NATIVE(pAddr->m_sockaddr.sa_family); + else + return osl_Socket_FamilyInvalid; +} + +/*****************************************************************************/ +/* osl_getInetPortOfSocketAddr */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getInetPortOfSocketAddr(oslSocketAddr pAddr) +{ + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + if ( (pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet))) + return ntohs(pSystemInetAddr->sin_port); + } + return OSL_INVALID_PORT; +} + +/*****************************************************************************/ +/* osl_setInetPortOfSocketAddr */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setInetPortOfSocketAddr ( + oslSocketAddr pAddr, + sal_Int32 Port) +{ + if (pAddr == NULL) + return sal_False; + + struct sockaddr_in* pSystemInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + if (pSystemInetAddr->sin_family != FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + return sal_False; + + pSystemInetAddr->sin_port= htons((short)Port); + return sal_True; +} + +/*****************************************************************************/ +/* osl_getHostnameOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getHostnameOfSocketAddr ( + oslSocketAddr Addr, + rtl_uString **strHostName) +{ + oslHostAddr pAddr= osl_createHostAddrByAddr (Addr); + + if (pAddr) + { + rtl_uString_newFromString(strHostName, pAddr->pHostName); + + osl_destroyHostAddr(pAddr); + + return osl_Socket_Ok; + } + + return osl_Socket_Error; +} + +/*****************************************************************************/ +/* osl_getDottedInetAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getDottedInetAddrOfSocketAddr ( + oslSocketAddr pAddr, + rtl_uString **strDottedInetAddr) +{ + sal_Char *pDotted; + + if (pAddr == NULL) + return osl_Socket_Error; + + struct sockaddr_in *pSystemInetAddr = (struct sockaddr_in*) &(pAddr->m_sockaddr); + if (pSystemInetAddr->sin_family != FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + return osl_Socket_Error; + + pDotted = inet_ntoa (pSystemInetAddr->sin_addr); + rtl_string2UString( + strDottedInetAddr, pDotted, strlen (pDotted), + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + OSL_ASSERT(*strDottedInetAddr != 0); + + return osl_Socket_Ok; +} + +/*****************************************************************************/ +/* osl_createSocket */ +/*****************************************************************************/ +oslSocket SAL_CALL osl_createSocket ( + oslAddrFamily Family, + oslSocketType Type, + oslProtocol Protocol) +{ + /* alloc memory */ + oslSocket pSocket = __osl_createSocketImpl(0); + + if (pSocket == NULL) + return 0; + + /* create socket */ + pSocket->m_Socket= socket(FAMILY_TO_NATIVE(Family), + TYPE_TO_NATIVE(Type), + PROTOCOL_TO_NATIVE(Protocol)); + + /* creation failed => free memory */ + if(pSocket->m_Socket == OSL_INVALID_SOCKET) + { + __osl_destroySocketImpl(pSocket); + pSocket= 0; + } + else + { + pSocket->m_Flags = 0; + pSocket->m_CloseCallback = NULL; + pSocket->m_CallbackArg = NULL; + } + + return pSocket; +} + +void SAL_CALL osl_acquireSocket( oslSocket pSocket ) +{ + osl_incrementInterlockedCount( &(pSocket->m_nRefCount) ); +} + +void SAL_CALL osl_releaseSocket( oslSocket pSocket ) +{ + if( pSocket && 0 == osl_decrementInterlockedCount( &(pSocket->m_nRefCount) ) ) + { + osl_closeSocket( pSocket ); + __osl_destroySocketImpl( pSocket ); + } +} + +/*****************************************************************************/ +/* osl_closeSocket */ +/*****************************************************************************/ +void SAL_CALL osl_closeSocket(oslSocket pSocket) +{ + /* socket already invalid */ + if(pSocket==0) + return; + + /* close */ + closesocket(pSocket->m_Socket); + + pSocket->m_Socket = OSL_INVALID_SOCKET; + + /* registrierten Callback ausfuehren */ + if (pSocket->m_CloseCallback != NULL) + { + pSocket->m_CloseCallback(pSocket->m_CallbackArg); + } +} + +/*****************************************************************************/ +/* osl_getLocalAddrOfSocket */ +/* Note that I rely on the fact that oslSocketAddr and struct sockaddr */ +/* are the same! I don't like it very much but see no other easy way */ +/* to conceal the struct sockaddr from the eyes of the user. */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getLocalAddrOfSocket(oslSocket pSocket) +{ + struct sockaddr Addr; + int AddrLen; + + if (pSocket == NULL) /* ENOTSOCK */ + return ((oslSocketAddr)NULL); + + AddrLen= sizeof(struct sockaddr); + + if (getsockname(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR) + return ((oslSocketAddr)NULL); + + oslSocketAddr pAddr = __osl_createSocketAddrFromSystem( &Addr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_getPeerAddrOfSocket */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getPeerAddrOfSocket(oslSocket pSocket) +{ + struct sockaddr Addr; + int AddrLen; + + if (pSocket == NULL) /* ENOTSOCK */ + return ((oslSocketAddr)NULL); + + AddrLen= sizeof(struct sockaddr); + + if (getpeername(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR) + return ((oslSocketAddr)NULL); + + oslSocketAddr pAddr = __osl_createSocketAddrFromSystem( &Addr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_bindAddrToSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_bindAddrToSocket ( oslSocket pSocket, oslSocketAddr pAddr) +{ + OSL_ASSERT( pAddr ); + + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + return (bind(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) != OSL_SOCKET_ERROR); +} + +/*****************************************************************************/ +/* osl_connectSocketTo */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_connectSocketTo ( + oslSocket pSocket, + oslSocketAddr pAddr, + const TimeValue* pTimeout) +{ + + if (pSocket == NULL) /* ENOTSOCK */ + return osl_Socket_Error; + + if (pAddr == NULL) /* EDESTADDRREQ */ + return osl_Socket_Error; + + if (!__osl_attemptSocketDialupImpl()) /* ENETDOWN */ + return osl_Socket_Error; + + if (pTimeout == NULL) + { + if(connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) == OSL_SOCKET_ERROR) + return osl_Socket_Error; + else + return osl_Socket_Ok; + } + else + { + fd_set fds; + int error; + struct timeval tv; + unsigned long Param; + oslSocketResult Result= osl_Socket_Ok; + + if (pSocket->m_Flags & OSL_SOCKET_FLAGS_NONBLOCKING) + { + if (connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) == OSL_SOCKET_ERROR) + { + switch (WSAGetLastError()) + { + case WSAEWOULDBLOCK: + case WSAEINPROGRESS: + return osl_Socket_InProgress; + + default: + return osl_Socket_Error; + } + } + else + return osl_Socket_Ok; + } + + /* set socket temporarily to non-blocking */ + Param= 1; + OSL_VERIFY(ioctlsocket( + pSocket->m_Socket, FIONBIO, &Param) != OSL_SOCKET_ERROR); + + /* initiate connect */ + if (connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) != OSL_SOCKET_ERROR) + { + /* immediate connection */ + + Param= 0; + ioctlsocket(pSocket->m_Socket, FIONBIO, &Param); + + return osl_Socket_Ok; + } + else + { + error = WSAGetLastError(); + + /* really an error or just delayed? */ + if (error != WSAEWOULDBLOCK && error != WSAEINPROGRESS) + { + Param= 0; + ioctlsocket(pSocket->m_Socket, FIONBIO, &Param); + + return osl_Socket_Error; + } + } + + /* prepare select set for socket */ + FD_ZERO(&fds); + FD_SET(pSocket->m_Socket, &fds); + + /* divide milliseconds into seconds and microseconds */ + tv.tv_sec= pTimeout->Seconds; + tv.tv_usec= pTimeout->Nanosec / 1000L; + + /* select */ + error= select(pSocket->m_Socket+1, + 0, + &fds, + 0, + &tv); + + if (error > 0) /* connected */ + { + OSL_POSTCOND( + FD_ISSET(pSocket->m_Socket, &fds), + "osl_connectSocketTo(): select returned but socket not set\n"); + + Result= osl_Socket_Ok; + + } + else if(error < 0) /* error */ + { + /* errno == EBADF: most probably interrupted by close() */ + if(WSAGetLastError() == WSAEBADF) + { + /* do not access pSockImpl because it is about to be or */ + /* already destroyed */ + return osl_Socket_Interrupted; + } + else + Result= osl_Socket_Error; + + } + else /* timeout */ + Result= osl_Socket_TimedOut; + + + /* clean up */ + Param= 0; + ioctlsocket(pSocket->m_Socket, FIONBIO, &Param); + + return Result; + } +} + +/*****************************************************************************/ +/* osl_listenOnSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_listenOnSocket ( + oslSocket pSocket, + sal_Int32 MaxPendingConnections) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + return (listen(pSocket->m_Socket, + MaxPendingConnections == -1 ? + SOMAXCONN : + MaxPendingConnections) != OSL_SOCKET_ERROR); +} + +/*****************************************************************************/ +/* osl_acceptConnectionOnSocket */ +/*****************************************************************************/ +oslSocket SAL_CALL osl_acceptConnectionOnSocket ( + oslSocket pSocket, + oslSocketAddr* ppAddr) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return ((oslSocket)NULL); + + SOCKET Connection; + if(ppAddr) + { + if( *ppAddr ) + { + osl_destroySocketAddr( *ppAddr ); + *ppAddr = 0; + } + int AddrLen= sizeof(struct sockaddr); + + /* user wants to know peer Addr */ + struct sockaddr Addr; + + Connection= accept(pSocket->m_Socket, &Addr, &AddrLen); + OSL_ASSERT(AddrLen == sizeof(struct sockaddr)); + + if(Connection != OSL_SOCKET_ERROR) + *ppAddr= __osl_createSocketAddrFromSystem(&Addr); + else + *ppAddr = NULL; + } + else + { + /* user is not interested in peer-addr */ + Connection= accept(pSocket->m_Socket, 0, 0); + } + + /* accept failed? */ + if(Connection == OSL_SOCKET_ERROR) + return ((oslSocket)NULL); + + /* alloc memory */ + oslSocket pConnectionSocket; + pConnectionSocket= __osl_createSocketImpl(Connection); + + pConnectionSocket->m_Flags = 0; + pConnectionSocket->m_CloseCallback = NULL; + pConnectionSocket->m_CallbackArg = NULL; + + return pConnectionSocket; +} + +/*****************************************************************************/ +/* osl_receiveSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receiveSocket ( + oslSocket pSocket, + void* pBuffer, + sal_uInt32 BytesToRead, + oslSocketMsgFlag Flag) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return osl_Socket_Error; + + return recv(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToRead, + MSG_FLAG_TO_NATIVE(Flag)); +} + +/*****************************************************************************/ +/* osl_receiveFromSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receiveFromSocket ( + oslSocket pSocket, + oslSocketAddr SenderAddr, + void* pBuffer, + sal_uInt32 BufferSize, + oslSocketMsgFlag Flag) +{ + struct sockaddr *pSystemSockAddr = 0; + int AddrLen = 0; + if( SenderAddr ) + { + AddrLen = sizeof( struct sockaddr ); + pSystemSockAddr = &(SenderAddr->m_sockaddr); + } + + if (pSocket == NULL) /* ENOTSOCK */ + return osl_Socket_Error; + + return recvfrom(pSocket->m_Socket, + (sal_Char*)pBuffer, + BufferSize, + MSG_FLAG_TO_NATIVE(Flag), + pSystemSockAddr, + &AddrLen); +} + +/*****************************************************************************/ +/* osl_sendSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendSocket ( + oslSocket pSocket, + const void* pBuffer, + sal_uInt32 BytesToSend, + oslSocketMsgFlag Flag) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return osl_Socket_Error; + + return send(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, + MSG_FLAG_TO_NATIVE(Flag)); +} + +/*****************************************************************************/ +/* osl_sendToSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendToSocket ( + oslSocket pSocket, + oslSocketAddr ReceiverAddr, + const void* pBuffer, + sal_uInt32 BytesToSend, + oslSocketMsgFlag Flag) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return osl_Socket_Error; + + /* ReceiverAddr might be 0 when used on a connected socket. */ + /* Then sendto should behave like send. */ + + struct sockaddr *pSystemSockAddr = 0; + if( ReceiverAddr ) + pSystemSockAddr = &(ReceiverAddr->m_sockaddr); + + return sendto(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, + MSG_FLAG_TO_NATIVE(Flag), + pSystemSockAddr, + pSystemSockAddr == 0 ? 0 : sizeof(struct sockaddr)); +} + +/*****************************************************************************/ +/* osl_readSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_readSocket( oslSocket pSocket, void *pBuffer, sal_Int32 n ) +{ + sal_uInt8 * Ptr = (sal_uInt8 *)pBuffer; + + OSL_ASSERT( pSocket); + + /* loop until all desired bytes were read or an error occured */ + sal_uInt32 BytesRead= 0; + sal_uInt32 BytesToRead= n; + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receiveSocket(pSocket, + Ptr, + BytesToRead, + osl_Socket_MsgNormal); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToRead -= RetVal; + BytesRead += RetVal; + Ptr += RetVal; + } + + return BytesRead; +} + +/*****************************************************************************/ +/* osl_writeSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_writeSocket( oslSocket pSocket, const void *pBuffer, sal_Int32 n ) +{ + OSL_ASSERT( pSocket ); + + /* loop until all desired bytes were send or an error occured */ + sal_uInt32 BytesSend= 0; + sal_uInt32 BytesToSend= n; + sal_uInt8 *Ptr = ( sal_uInt8 * )pBuffer; + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendSocket( pSocket,Ptr,BytesToSend,osl_Socket_MsgNormal); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToSend -= RetVal; + BytesSend += RetVal; + Ptr += RetVal; + + } + return BytesSend; +} + + +/*****************************************************************************/ +/* osl_isReceiveReady */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isReceiveReady ( + oslSocket pSocket, + const TimeValue* pTimeout) +{ + fd_set fds; + struct timeval tv; + + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + FD_ZERO(&fds); + FD_SET(pSocket->m_Socket, &fds); + + if (pTimeout) + { + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000L; + } + + return (select(pSocket->m_Socket + 1, /* no of sockets to monitor */ + &fds, /* check read operations */ + 0, /* check write ops */ + 0, /* ckeck for OOB */ + (pTimeout) ? &tv : 0)==1); /* use timeout? */ +} + +/*****************************************************************************/ +/* osl_isSendReady */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isSendReady ( + oslSocket pSocket, + const TimeValue* pTimeout) +{ + fd_set fds; + struct timeval tv; + + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + FD_ZERO(&fds); + FD_SET(pSocket->m_Socket, &fds); + + if (pTimeout) + { + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000L; + } + + return (select(pSocket->m_Socket + 1, /* no of sockets to monitor */ + 0, /* check read operations */ + &fds, /* check write ops */ + 0, /* ckeck for OOB */ + (pTimeout) ? &tv : 0)==1); /* use timeout? */ +} + +/*****************************************************************************/ +/* osl_isExceptionPending */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isExceptionPending ( + oslSocket pSocket, + const TimeValue* pTimeout) +{ + fd_set fds; + struct timeval tv; + + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + FD_ZERO(&fds); + FD_SET(pSocket->m_Socket, &fds); + + if (pTimeout) + { + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000L; + } + + return (select(pSocket->m_Socket + 1, /* no of sockets to monitor */ + 0, /* check read operations */ + 0, /* check write ops */ + &fds, /* ckeck for OOB */ + (pTimeout) ? &tv : 0)==1); /* use timeout? */ +} + +/*****************************************************************************/ +/* osl_shutdownSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_shutdownSocket ( + oslSocket pSocket, + oslSocketDirection Direction) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + return (shutdown(pSocket->m_Socket, DIRECTION_TO_NATIVE(Direction))==0); +} + +/*****************************************************************************/ +/* osl_getSocketOption */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getSocketOption ( + oslSocket pSocket, + oslSocketOptionLevel Level, + oslSocketOption Option, + void* pBuffer, + sal_uInt32 BufferLen) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return osl_Socket_Error; + + if (getsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(Level), + OPTION_TO_NATIVE(Option), + (sal_Char*)pBuffer, + (int*)&BufferLen) == -1) + { + return -1; + } + + return (sal_Int32)BufferLen; +} + +/*****************************************************************************/ +/* osl_setSocketOption */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setSocketOption ( + oslSocket pSocket, + oslSocketOptionLevel Level, + oslSocketOption Option, + void* pBuffer, + sal_uInt32 BufferLen) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + return(setsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(Level), + OPTION_TO_NATIVE(Option), + (sal_Char*)pBuffer, + BufferLen) == 0); +} + +/*****************************************************************************/ +/* osl_enableNonBlockingMode */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_enableNonBlockingMode ( oslSocket pSocket, sal_Bool On) +{ + unsigned long Param= On ? 1 : 0; + + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + pSocket->m_Flags = Param ? + (pSocket->m_Flags | OSL_SOCKET_FLAGS_NONBLOCKING) : + (pSocket->m_Flags & ~OSL_SOCKET_FLAGS_NONBLOCKING) ; + + return ( + ioctlsocket(pSocket->m_Socket, FIONBIO, &Param) != OSL_SOCKET_ERROR); +} + +/*****************************************************************************/ +/* osl_isNonBlockingMode */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isNonBlockingMode(oslSocket pSocket) +{ + if (pSocket == NULL) /* ENOTSOCK */ + return sal_False; + + return (sal_Bool)((pSocket->m_Flags & OSL_SOCKET_FLAGS_NONBLOCKING) != 0); +} + +/*****************************************************************************/ +/* osl_getSocketType */ +/*****************************************************************************/ +oslSocketType SAL_CALL osl_getSocketType(oslSocket pSocket) +{ + int Type=0; + int TypeSize= sizeof(Type); + + if (pSocket == NULL) /* ENOTSOCK */ + return osl_Socket_TypeInvalid; + + if(getsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(osl_Socket_LevelSocket), + OPTION_TO_NATIVE(osl_Socket_OptionType), + (sal_Char *)&Type, + &TypeSize) == -1) + { + /* error */ + return osl_Socket_TypeInvalid; + } + + return TYPE_FROM_NATIVE(Type); +} + +/*****************************************************************************/ +/* osl_getLastSocketErrorDescription */ +/*****************************************************************************/ +void SAL_CALL osl_getLastSocketErrorDescription ( + oslSocket /*Socket*/, + rtl_uString **strError) +{ + int error; + + switch(error = WSAGetLastError()) + { + case WSAENOTSOCK: + rtl_uString_newFromAscii (strError, "WSAENOTSOCK, Socket operation on non-socket. A socket created in one process is used by another process."); + break; + + case WSAEDESTADDRREQ: + rtl_uString_newFromAscii (strError, "WSAEDESTADDRREQ, Destination Addr required"); + break; + + case WSAEMSGSIZE: + rtl_uString_newFromAscii (strError, "WSAEMSGSIZE, Message too long"); + break; + + case WSAEPROTOTYPE: + rtl_uString_newFromAscii (strError, "WSAEPROTOTYPE, Protocol wrong type for socket"); + break; + + case WSAENOPROTOOPT: + rtl_uString_newFromAscii (strError, "WSAENOPROTOOPT, Protocol not available"); + break; + + case WSAEPROTONOSUPPORT: + rtl_uString_newFromAscii (strError, "WSAEPROTONOSUPPORT, Protocol not supported"); + break; + + case WSAESOCKTNOSUPPORT: + rtl_uString_newFromAscii (strError, "WSAESOCKTNOSUPPORT, Socket type not supported"); + break; + + case WSAEOPNOTSUPP: + rtl_uString_newFromAscii (strError, "WSAEOPNOTSUPP, Operation not supported on socket"); + break; + + case WSAEPFNOSUPPORT: + rtl_uString_newFromAscii (strError, "WSAEPFNOSUPPORT, Protocol family not supported"); + break; + + case WSAEAFNOSUPPORT: + rtl_uString_newFromAscii (strError, "WSEAFNOSUPPORT, Addr family not supported by protocol family"); + break; + + case WSAEADDRINUSE: + rtl_uString_newFromAscii (strError, "WSAEADDRINUSE, Triggered by bind() because a process went down without closing a socket."); + break; + + case WSAEADDRNOTAVAIL: + rtl_uString_newFromAscii (strError, "WSAEADDRNOTAVAIL, Can't assign requested Addr"); + break; + + case WSAENETDOWN: + rtl_uString_newFromAscii (strError, "WSAENETDOWN, Network is down"); + break; + + case WSAENETUNREACH: + rtl_uString_newFromAscii (strError, "WSAENETUNREACH, Network is unreachable"); + break; + + case WSAENETRESET: + rtl_uString_newFromAscii (strError, "WSAENETRESET, Network dropped connection or reset"); + break; + + case WSAECONNABORTED: + rtl_uString_newFromAscii (strError, "WSAECONNABORTED, Software caused connection abort"); + break; + + case WSAECONNRESET: + rtl_uString_newFromAscii (strError, "WSAECONNRESET, Connection reset by peer"); + break; + + case WSAENOBUFS: + rtl_uString_newFromAscii (strError, "WSAENOBUFS, No buffer space available."); + break; + + case WSAEISCONN: + rtl_uString_newFromAscii (strError, "WSAEISCONN, Socket is already connected"); + break; + + case WSAENOTCONN: + rtl_uString_newFromAscii (strError, "WSAENOTCONN, Socket is not connected"); + break; + + case WSAESHUTDOWN: + rtl_uString_newFromAscii (strError, "WSAESHUTDOWN, Can't send after socket shutdown"); + break; + + case WSAETIMEDOUT: + rtl_uString_newFromAscii (strError, "WSAETIMEDOUT, Connection timed out"); + break; + + case WSAECONNREFUSED: + rtl_uString_newFromAscii (strError, "WSAECONNREFUSED, Connection refused"); + break; + + case WSAEHOSTDOWN: + rtl_uString_newFromAscii (strError, "WSAEHOSTDOWN, Networking subsystem not started"); + break; + + case WSAEHOSTUNREACH: + rtl_uString_newFromAscii (strError, "WSAEHOSTUNREACH, No route to host"); + break; + + case WSAEWOULDBLOCK: + rtl_uString_newFromAscii (strError, "WSAEWOULDBLOCK, Operation would block"); + break; + + case WSAEINPROGRESS: + rtl_uString_newFromAscii (strError, "WSAEINPROGRESS, Operation now in progress"); + break; + + case WSAEALREADY: + rtl_uString_newFromAscii (strError, "WSAEALREADY, Operation already in progress"); + break; + + case WSAEINTR: + rtl_uString_newFromAscii (strError, "WSAEALREADY, Operation was interrupted"); + break; + + case WSAEBADF: + rtl_uString_newFromAscii (strError, "WSAEBADF, Bad file number"); + break; + + case WSAEACCES: + rtl_uString_newFromAscii (strError, "WSAEACCES, Access is denied"); + break; + + case WSAEFAULT: + rtl_uString_newFromAscii (strError, "WSAEFAULT, Bad memory Addr"); + break; + + case WSAEINVAL: + rtl_uString_newFromAscii (strError, "WSAEINVAL, The socket has not been bound with bind() or is already connected"); + break; + + case WSAEMFILE: + rtl_uString_newFromAscii (strError, "WSAEMFILE, No more file descriptors are available"); + break; + + case WSAETOOMANYREFS: + rtl_uString_newFromAscii (strError, "WSAETOOMANYREFS, Undocumented WinSock error"); + break; + + case WSAENAMETOOLONG: + rtl_uString_newFromAscii (strError, "WSAENAMETOOLONG, Undocumented WinSock error"); + break; + + case WSAENOTEMPTY: + rtl_uString_newFromAscii (strError, "WSAENOTEMPTY, Undocumented WinSock error"); + break; + + case WSAEPROCLIM: + rtl_uString_newFromAscii (strError, "WSAEPROCLIM, Undocumented WinSock error"); + break; + + case WSAEUSERS: + rtl_uString_newFromAscii (strError, "WSAEUSERS, Undocumented WinSock error"); + break; + + case WSAEDQUOT: + rtl_uString_newFromAscii (strError, "WSAEDQUOT, Undocumented WinSock error"); + break; + + case WSAESTALE: + rtl_uString_newFromAscii (strError, "WSAESTALE, Undocumented WinSock error"); + break; + + case WSAEREMOTE: + rtl_uString_newFromAscii (strError, "WSAEREMOTE, Undocumented WinSock error"); + break; + + case WSAEDISCON: + rtl_uString_newFromAscii (strError, "WSAEDISCON, Circuit was gracefully terminated"); + break; + + case WSASYSNOTREADY: + rtl_uString_newFromAscii (strError, "WSASYSNOTREADY, The underlying network subsystem is not ready for network communication"); + break; + + case WSAVERNOTSUPPORTED: + rtl_uString_newFromAscii (strError, "WSAVERNOTSUPPORTED, The version of Windows Sockets API support requested is not provided by this particular Windows Sockets implementation"); + break; + + case WSANOTINITIALISED: + rtl_uString_newFromAscii (strError, "WSANOTINITIALISED, WSAStartup() has not been called"); + break; + + case WSAHOST_NOT_FOUND: + rtl_uString_newFromAscii (strError, "WSAHOST_NOT_FOUND, Authoritative answer host not found"); + break; + + case WSATRY_AGAIN: + rtl_uString_newFromAscii (strError, "WSATRY_AGAIN, Non-authoritative answer host not found or SERVERFAIL"); + break; + + case WSANO_RECOVERY: + rtl_uString_newFromAscii (strError, "WSANO_RECOVERY, Non recoverable errors, FORMERR, REFUSED, NOTIMP"); + break; + + case WSANO_DATA: + rtl_uString_newFromAscii (strError, "WSANO_DATA or WSANO_ADDRESS, Valid name, no data record of requested type"); + break; + + default: + { + sal_Unicode message[128]; + + wsprintfW(reinterpret_cast<LPWSTR>(message), L"Unknown WinSock Error Number %d", error); + rtl_uString_newFromStr (strError, message); + } + + return; + + } +} + +/*****************************************************************************/ +/* osl_getLastSocketError */ +/*****************************************************************************/ +oslSocketError SAL_CALL osl_getLastSocketError(oslSocket /*Socket*/) +{ + return ERROR_FROM_NATIVE(WSAGetLastError()); +} + +/*****************************************************************************/ +/* SocketSet */ +/*****************************************************************************/ +typedef struct _TSocketSetImpl +{ + fd_set m_Set; /* the set of descriptors */ + +} TSocketSetImpl; + +/*****************************************************************************/ +/* osl_createSocketSet */ +/*****************************************************************************/ +oslSocketSet SAL_CALL osl_createSocketSet() +{ + TSocketSetImpl* pSet; + + pSet = (TSocketSetImpl*) rtl_allocateMemory(sizeof(TSocketSetImpl)); + + if(pSet) + { + FD_ZERO(&pSet->m_Set); + } + + return (oslSocketSet)pSet; +} + +/*****************************************************************************/ +/* osl_destroySocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_destroySocketSet (oslSocketSet Set) +{ + if(Set) + rtl_freeMemory(Set); +} + +/*****************************************************************************/ +/* osl_clearSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_clearSocketSet (oslSocketSet Set) +{ + TSocketSetImpl* pSet; + + pSet= (TSocketSetImpl*)Set; + + if (pSet) + FD_ZERO(&pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_addToSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_addToSocketSet ( + oslSocketSet Set, + oslSocket Socket) +{ + TSocketSetImpl* pSet; + oslSocketImpl* pSockImpl; + + pSet= (TSocketSetImpl*)Set; + pSockImpl= (oslSocketImpl*)Socket; + + if (pSet && pSockImpl) + FD_SET(pSockImpl->m_Socket, &pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_removeFromSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_removeFromSocketSet ( + oslSocketSet Set, + oslSocket Socket) +{ + TSocketSetImpl* pSet; + oslSocketImpl* pSockImpl; + + pSet= (TSocketSetImpl*)Set; + pSockImpl= (oslSocketImpl*)Socket; + + if (pSet && pSockImpl) + FD_CLR(pSockImpl->m_Socket, &pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_isInSocketSet */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isInSocketSet ( + oslSocketSet Set, + oslSocket Socket) +{ + TSocketSetImpl* pSet; + oslSocketImpl* pSockImpl; + + pSet= (TSocketSetImpl*)Set; + pSockImpl= (oslSocketImpl*)Socket; + + if (pSet && pSockImpl) + return (FD_ISSET(pSockImpl->m_Socket, &pSet->m_Set) != 0); + else + return sal_False; +} + +/*****************************************************************************/ +/* osl_demultiplexSocketEvents */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_demultiplexSocketEvents ( + oslSocketSet IncomingSet, + oslSocketSet OutgoingSet, + oslSocketSet OutOfBandSet, + const TimeValue* pTimeout) +{ + int MaxHandle= 0; + struct timeval tv; + TSocketSetImpl* pInSet; + TSocketSetImpl* pOutSet; + TSocketSetImpl* pOOBSet; + + if(pTimeout) + { + /* divide milliseconds into seconds and microseconds */ + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000L; + } + + /* map opaque data to impl-types */ + pInSet= (TSocketSetImpl*)IncomingSet; + pOutSet= (TSocketSetImpl*)OutgoingSet; + pOOBSet= (TSocketSetImpl*)OutOfBandSet; + + return select(MaxHandle, /* redundant in WIN32 */ + pInSet ? &pInSet->m_Set : 0, + pOutSet ? &pOutSet->m_Set : 0, + pOOBSet ? &pOOBSet->m_Set : 0, + pTimeout ? &tv : 0); +} + +} diff --git a/sal/osl/w32/sockimpl.h b/sal/osl/w32/sockimpl.h new file mode 100644 index 000000000000..d1278ee8e6ac --- /dev/null +++ b/sal/osl/w32/sockimpl.h @@ -0,0 +1,108 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_SOCKETIMPL_H_ +#define _OSL_SOCKETIMPL_H_ + +#include <osl/socket.h> +#include <osl/interlck.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*****************************************************************************/ +/* oslSocketImpl */ +/*****************************************************************************/ +#define OSL_SOCKET_FLAGS_NONBLOCKING 0x0001 + +typedef void* (SAL_CALL * oslCloseCallback) (void*); + +struct oslSocketImpl { + oslInterlockedCount m_nRefCount; + SOCKET m_Socket; + int m_Flags; + oslCloseCallback m_CloseCallback; + void* m_CallbackArg; +}; + +struct oslSocketAddrImpl +{ + struct sockaddr m_sockaddr; + oslInterlockedCount m_nRefCount; +}; + +oslSocket __osl_createSocketImpl(SOCKET Socket); +void __osl_destroySocketImpl(oslSocket pImpl); + +/*****************************************************************************/ +/* oslSocketDialupImpl */ +/*****************************************************************************/ +#define INTERNET_MODULE_NAME "wininet.dll" + +#define INTERNET_CONNECTION_MODEM 0x00000001L +#define INTERNET_CONNECTION_LAN 0x00000002L +#define INTERNET_CONNECTION_HANGUP 0x80000000L + +typedef DWORD (WINAPI *INTERNETATTEMPTCONNECT) ( + DWORD dwReserved); +typedef BOOL (WINAPI *INTERNETAUTODIAL) ( + DWORD dwFlags, DWORD dwReserved); +typedef BOOL (WINAPI *INTERNETAUTODIALHANGUP) ( + DWORD dwReserved); +typedef BOOL (WINAPI *INTERNETGETCONNECTEDSTATE) ( + LPDWORD lpdwFlags, DWORD dwReserved); + +typedef struct osl_socket_dialup_impl_st +{ + CRITICAL_SECTION m_hMutex; + HINSTANCE m_hModule; + INTERNETATTEMPTCONNECT m_pfnAttemptConnect; + INTERNETAUTODIAL m_pfnAutodial; + INTERNETAUTODIALHANGUP m_pfnAutodialHangup; + INTERNETGETCONNECTEDSTATE m_pfnGetConnectedState; + DWORD m_dwFlags; +} oslSocketDialupImpl; + +static oslSocketDialupImpl* __osl_createSocketDialupImpl (void); +static void __osl_initSocketDialupImpl (oslSocketDialupImpl *pImpl); +static void __osl_destroySocketDialupImpl (oslSocketDialupImpl *pImpl); + +static sal_Bool __osl_querySocketDialupImpl (void); +static sal_Bool __osl_attemptSocketDialupImpl (void); + +/*****************************************************************************/ +/* The End */ +/*****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/sal/osl/w32/system.h b/sal/osl/w32/system.h new file mode 100644 index 000000000000..1bd86994e6ce --- /dev/null +++ b/sal/osl/w32/system.h @@ -0,0 +1,126 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if OSL_DEBUG_LEVEL == 0 +# define NO_DEBUG_CRT +#endif + +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x0400 +# define _CTYPE_DISABLE_MACROS /* wg. dynamischer C-Runtime MH */ +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <malloc.h> +#include <limits.h> +#include <process.h> +#include <time.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <io.h> +#include <share.h> +#include <direct.h> + +/* Must define this else build breaks because Winsock2.h + includes Windows.h and without WIN32_LEAN_AND_MEAN + also includes mswsock.h which needs a forward typedef + of SOCKET ... +*/ +#define WIN32_LEAN_AND_MEAN + +#ifdef GCC + // windows.h includes winsock2.h + // if _WIN32_WINNT > 0x0400 + // so someone cannot include winsock.h + // at the same time without patching + // windows.h + #include <windows.h> +#ifdef __MINGW32__ + #include <winsock2.h> + #include <ws2tcpip.h> +#endif + #include <shlobj.h> + #ifndef NO_DEBUG_CRT + #include <crtdbg.h> + #endif +#else + // winsock2.h includes windows.h + #pragma warning(push,1) /* disable warnings within system headers */ + #pragma warning(disable:4917) + #include <winsock2.h> + #include <wsipx.h> + #include <shlobj.h> + #ifndef NO_DEBUG_CRT + #include <crtdbg.h> + #endif + #pragma warning(pop) +#endif + +#define _MAX_CMD 4096 /* maximum length of commandline */ +/* #define _MAX_ENV 4096 maximum length of environment var (isn't used anywhere) */ + +#ifdef GCC + # ifndef SA_FAMILY_DECL + # define SA_FAMILY_DECL short sa_family + # endif + + typedef struct sockaddr_ipx { + SA_FAMILY_DECL; + char sa_netnum[4]; + char sa_nodenum[6]; + unsigned short sa_socket; + } SOCKADDR_IPX; + + # define NSPROTO_IPX 1000 + # define NSPROTO_SPX 1256 + # define NSPROTO_SPXII 1257 +#endif // #ifdef GCC + +#ifdef _DLL_ + +#ifdef __cplusplus + extern "C" DWORD g_dwPlatformId; +#else + extern DWORD g_dwPlatformId; +#endif // #ifdef __cplusplus + + #define IS_NT (g_dwPlatformId == VER_PLATFORM_WIN32_NT) +#else + +#ifdef __cplusplus + extern "C" DWORD GetPlatformId(void); +#else + extern DWORD GetPlatformId(void); +#endif // #ifdef __cplusplus + + #define IS_NT (GetPlatformId() == VER_PLATFORM_WIN32_NT) +#endif // #ifdef _DLL_ + diff --git a/sal/osl/w32/tempfile.cxx b/sal/osl/w32/tempfile.cxx new file mode 100644 index 000000000000..6a3d2549004a --- /dev/null +++ b/sal/osl/w32/tempfile.cxx @@ -0,0 +1,274 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define UNICODE +#define _UNICODE +#define _WIN32_WINNT_0x0500 +#include "systools/win32/uwinapi.h" + +#include "osl/file.h" + +#include "file_error.h" +#include "file_url.h" +#include "path_helper.hxx" + +#include "osl/diagnose.h" + +#include <malloc.h> +#include <tchar.h> + +//##################################################### +#define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0]))) + +// Allocate n number of t's on the stack return a pointer to it in p +#ifdef __MINGW32__ +#define STACK_ALLOC(p, t, n) (p) = reinterpret_cast<t*>(_alloca((n)*sizeof(t))); +#else +#define STACK_ALLOC(p, t, n) __try {(p) = reinterpret_cast<t*>(_alloca((n)*sizeof(t)));} \ + __except(EXCEPTION_EXECUTE_HANDLER) {(p) = 0;} +#endif + +extern "C" oslFileHandle SAL_CALL osl_createFileHandleFromOSHandle(HANDLE hFile, sal_uInt32 uFlags); + +//##################################################### +// Temp file functions +//##################################################### + +static oslFileError osl_setup_base_directory_impl_( + rtl_uString* pustrDirectoryURL, + rtl_uString** ppustr_base_dir) +{ + rtl_uString* dir_url = 0; + rtl_uString* dir = 0; + oslFileError error = osl_File_E_None; + + if (pustrDirectoryURL) + rtl_uString_assign(&dir_url, pustrDirectoryURL); + else + error = osl_getTempDirURL(&dir_url); + + if (osl_File_E_None == error) + { + error = _osl_getSystemPathFromFileURL(dir_url, &dir, sal_False); + rtl_uString_release(dir_url); + } + + if (osl_File_E_None == error ) + { + rtl_uString_assign(ppustr_base_dir, dir); + rtl_uString_release(dir); + } + + return error; +} + +//##################################################### +static oslFileError osl_setup_createTempFile_impl_( + rtl_uString* pustrDirectoryURL, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL, + rtl_uString** ppustr_base_dir, + sal_Bool* b_delete_on_close) +{ + oslFileError osl_error; + + OSL_PRECOND(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!"); + + if ((0 == pHandle) && (0 == ppustrTempFileURL)) + { + osl_error = osl_File_E_INVAL; + } + else + { + osl_error = osl_setup_base_directory_impl_( + pustrDirectoryURL, ppustr_base_dir); + + *b_delete_on_close = (sal_Bool)(0 == ppustrTempFileURL); + } + + return osl_error; +} + +//##################################################### +static oslFileError osl_win32_GetTempFileName_impl_( + rtl_uString* base_directory, LPWSTR temp_file_name) +{ + oslFileError osl_error = osl_File_E_None; + + if (0 == GetTempFileNameW( + reinterpret_cast<LPCWSTR>(rtl_uString_getStr(base_directory)), + L"", + 0, + temp_file_name)) + { + osl_error = oslTranslateFileError(GetLastError()); + } + + return osl_error; +} + +//##################################################### +static sal_Bool osl_win32_CreateFile_impl_( + LPCWSTR file_name, sal_Bool b_delete_on_close, oslFileHandle* p_handle) +{ + DWORD flags = FILE_ATTRIBUTE_NORMAL; + HANDLE hFile; + + OSL_ASSERT(p_handle); + + if (b_delete_on_close) + flags |= FILE_FLAG_DELETE_ON_CLOSE; + + hFile = CreateFileW( + file_name, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + TRUNCATE_EXISTING, + flags, + NULL); + + // @@@ ERROR HANDLING @@@ + if (IsValidHandle(hFile)) + *p_handle = osl_createFileHandleFromOSHandle(hFile, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + + return (sal_Bool)IsValidHandle(hFile); +} + +//############################################# +static oslFileError osl_createTempFile_impl_( + rtl_uString* base_directory, + LPWSTR tmp_name, + sal_Bool b_delete_on_close, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL) +{ + oslFileError osl_error; + + do + { + osl_error = osl_win32_GetTempFileName_impl_(base_directory, tmp_name); + + /* if file could not be opened try again */ + + if ((osl_File_E_None != osl_error) || (0 == pHandle) || + osl_win32_CreateFile_impl_(tmp_name, b_delete_on_close, pHandle)) + break; + + } while(1); // try until success + + if ((osl_File_E_None == osl_error) && !b_delete_on_close) + { + rtl_uString* pustr = 0; + rtl_uString_newFromStr(&pustr, reinterpret_cast<const sal_Unicode*>(tmp_name)); + osl_getFileURLFromSystemPath(pustr, ppustrTempFileURL); + rtl_uString_release(pustr); + } + + return osl_error; +} + +//############################################# +oslFileError SAL_CALL osl_createTempFile( + rtl_uString* pustrDirectoryURL, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL) +{ + rtl_uString* base_directory = 0; + LPWSTR tmp_name; + sal_Bool b_delete_on_close; + oslFileError osl_error; + + osl_error = osl_setup_createTempFile_impl_( + pustrDirectoryURL, + pHandle, + ppustrTempFileURL, + &base_directory, + &b_delete_on_close); + + if (osl_File_E_None != osl_error) + return osl_error; + + /* allocate enough space on the stack, the file name can not be longer than MAX_PATH */ + STACK_ALLOC(tmp_name, WCHAR, (rtl_uString_getLength(base_directory) + MAX_PATH)); + + if (tmp_name) + { + osl_createTempFile_impl_( + base_directory, + tmp_name, + b_delete_on_close, + pHandle, + ppustrTempFileURL); + } + else // stack alloc failed + { + osl_error = osl_File_E_NOMEM; + } + + if (base_directory) + rtl_uString_release(base_directory); + + return osl_error; +} + +//############################################# +oslFileError SAL_CALL osl_getTempDirURL(rtl_uString** pustrTempDir) +{ + ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); + LPWSTR lpBuffer = ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer); + DWORD nBufferLength = aBuffer.getBufSizeInSymbols() - 1; + + DWORD nLength; + oslFileError error; + + nLength = GetTempPathW( aBuffer.getBufSizeInSymbols(), lpBuffer ); + + if ( nLength > nBufferLength ) + { + // the provided path has invalid length + error = osl_File_E_NOENT; + } + else if ( nLength ) + { + rtl_uString *ustrTempPath = NULL; + + if ( '\\' == lpBuffer[nLength-1] ) + lpBuffer[nLength-1] = 0; + + rtl_uString_newFromStr( &ustrTempPath, reinterpret_cast<const sal_Unicode*>(lpBuffer) ); + + error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir ); + + rtl_uString_release( ustrTempPath ); + } + else + error = oslTranslateFileError( GetLastError() ); + + return error; +} + diff --git a/sal/osl/w32/thread.c b/sal/osl/w32/thread.c new file mode 100644 index 000000000000..88ce87cdf175 --- /dev/null +++ b/sal/osl/w32/thread.c @@ -0,0 +1,593 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <rtl/alloc.h> +#include <osl/time.h> +#include <osl/interlck.h> +#include <rtl/tencinfo.h> + +/* + Thread-data structure hidden behind oslThread: +*/ +typedef struct _osl_TThreadImpl +{ + HANDLE m_hThread; /* OS-handle used for all thread-functions */ + unsigned m_ThreadId; /* identifier for this thread */ + sal_Int32 m_nTerminationRequested; + oslWorkerFunction m_WorkerFunction; + void* m_pData; + +} osl_TThreadImpl; + +#define THREADIMPL_FLAGS_TERMINATE 0x0001 + +static unsigned __stdcall oslWorkerWrapperFunction(void* pData); +static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_uInt32 nFlags); + +/*****************************************************************************/ +/* oslWorkerWrapperFunction */ +/*****************************************************************************/ +static unsigned __stdcall oslWorkerWrapperFunction(void* pData) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData; + + /* Initialize COM */ + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + /* call worker-function with data */ + + pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData); + + CoUninitialize(); + + return (0); +} + +/*****************************************************************************/ +/* oslCreateThread */ +/*****************************************************************************/ +static oslThread oslCreateThread(oslWorkerFunction pWorker, + void* pThreadData, + sal_uInt32 nFlags) +{ + osl_TThreadImpl* pThreadImpl; + + /* alloc mem. for our internal data structure */ + pThreadImpl= malloc(sizeof(osl_TThreadImpl)); + + OSL_ASSERT(pThreadImpl); + + if ( pThreadImpl == 0 ) + { + return 0; + } + + pThreadImpl->m_WorkerFunction= pWorker; + pThreadImpl->m_pData= pThreadData; + pThreadImpl->m_nTerminationRequested= 0; + + pThreadImpl->m_hThread= + (HANDLE)_beginthreadex(NULL, /* no security */ + 0, /* default stack-size */ + oslWorkerWrapperFunction, /* worker-function */ + pThreadImpl, /* provide worker-function with data */ + nFlags, /* start thread immediately or suspended */ + &pThreadImpl->m_ThreadId); + + if(pThreadImpl->m_hThread == 0) + { + /* create failed */ + free(pThreadImpl); + return 0; + } + + return (oslThread)pThreadImpl; +} + +/*****************************************************************************/ +/* osl_createThread */ +/*****************************************************************************/ +oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker, + void* pThreadData) +{ + return oslCreateThread(pWorker, pThreadData, 0); +} + +/*****************************************************************************/ +/* osl_createSuspendedThread */ +/*****************************************************************************/ +oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker, + void* pThreadData) +{ + return oslCreateThread(pWorker, pThreadData, CREATE_SUSPENDED); +} + +/*****************************************************************************/ +/* osl_getThreadIdentifier */ +/*****************************************************************************/ +oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + if (pThreadImpl != NULL) + return ((oslThreadIdentifier)pThreadImpl->m_ThreadId); + else + return ((oslThreadIdentifier)GetCurrentThreadId()); +} + +/*****************************************************************************/ +/* osl_destroyThread */ +/*****************************************************************************/ +void SAL_CALL osl_destroyThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + if (Thread == 0) /* valid ptr? */ + { + /* thread already destroyed or not created */ + return; + } + + /* !!!! _exitthreadex does _not_ call CloseHandle !!! */ + CloseHandle( pThreadImpl->m_hThread ); + + /* free memory */ + free(Thread); +} + +/*****************************************************************************/ +/* osl_resumeThread */ +/*****************************************************************************/ +void SAL_CALL osl_resumeThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + OSL_ASSERT(pThreadImpl); /* valid ptr? */ + + ResumeThread(pThreadImpl->m_hThread); +} + +/*****************************************************************************/ +/* osl_suspendThread */ +/*****************************************************************************/ +void SAL_CALL osl_suspendThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + OSL_ASSERT(pThreadImpl); /* valid ptr? */ + + SuspendThread(pThreadImpl->m_hThread); +} + +/*****************************************************************************/ +/* osl_setThreadPriority */ +/*****************************************************************************/ +void SAL_CALL osl_setThreadPriority(oslThread Thread, + oslThreadPriority Priority) +{ + int winPriority; + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + OSL_ASSERT(pThreadImpl); /* valid ptr? */ + + + /* map enum to WIN32 levels + it would be faster and more elegant to preset + the enums, but that would require an #ifdef in + the exported header, which is not desired. + */ + switch(Priority) { + + case osl_Thread_PriorityHighest: + winPriority= THREAD_PRIORITY_HIGHEST; + break; + + case osl_Thread_PriorityAboveNormal: + winPriority= THREAD_PRIORITY_ABOVE_NORMAL; + break; + + case osl_Thread_PriorityNormal: + winPriority= THREAD_PRIORITY_NORMAL; + break; + + case osl_Thread_PriorityBelowNormal: + winPriority= THREAD_PRIORITY_BELOW_NORMAL; + break; + + case osl_Thread_PriorityLowest: + winPriority= THREAD_PRIORITY_LOWEST; + break; + + case osl_Thread_PriorityUnknown: + OSL_ASSERT(FALSE); /* only fools try this...*/ + + /* let release-version behave friendly */ + return; + + default: + OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/ + + /* let release-version behave friendly */ + return; + } + + SetThreadPriority(pThreadImpl->m_hThread, winPriority); +} + +/*****************************************************************************/ +/* osl_getThreadPriority */ +/*****************************************************************************/ +oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread) +{ + int winPriority; + oslThreadPriority Priority; + + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + /* invalid arguments ?*/ + if(pThreadImpl==0 || pThreadImpl->m_hThread==0) + { + return osl_Thread_PriorityUnknown; + } + + winPriority= + GetThreadPriority(pThreadImpl->m_hThread); + + + if(winPriority == THREAD_PRIORITY_ERROR_RETURN) + { + return osl_Thread_PriorityUnknown; + } + + /* map WIN32 priority to enum */ + switch(winPriority) + { + case THREAD_PRIORITY_TIME_CRITICAL: + case THREAD_PRIORITY_HIGHEST: + Priority= osl_Thread_PriorityHighest; + break; + + case THREAD_PRIORITY_ABOVE_NORMAL: + Priority= osl_Thread_PriorityAboveNormal; + break; + + case THREAD_PRIORITY_NORMAL: + Priority= osl_Thread_PriorityNormal; + break; + + case THREAD_PRIORITY_BELOW_NORMAL: + Priority= osl_Thread_PriorityBelowNormal; + break; + + case THREAD_PRIORITY_IDLE: + case THREAD_PRIORITY_LOWEST: + Priority= osl_Thread_PriorityLowest; + break; + + default: + OSL_ASSERT(FALSE); /* WIN32 API changed, incorporate new prio-level! */ + + /* release-version behaves friendly */ + Priority= osl_Thread_PriorityUnknown; + } + + return Priority; +} + +/*****************************************************************************/ +/* osl_isThreadRunning */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + /* invalid arguments ?*/ + if(pThreadImpl==0 || pThreadImpl->m_hThread==0) + { + return sal_False; + } + + return (sal_Bool)(WaitForSingleObject(pThreadImpl->m_hThread, 0) != WAIT_OBJECT_0); +} + +/*****************************************************************************/ +/* osl_joinWithThread */ +/*****************************************************************************/ +void SAL_CALL osl_joinWithThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + /* invalid arguments?*/ + if(pThreadImpl==0 || pThreadImpl->m_hThread==0) + { + /* assume thread is not running */ + return; + } + + WaitForSingleObject(pThreadImpl->m_hThread, INFINITE); +} + +/*****************************************************************************/ +/* osl_waitThread */ +/*****************************************************************************/ +void SAL_CALL osl_waitThread(const TimeValue* pDelay) +{ + if (pDelay) + { + DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L; + + Sleep(millisecs); + } +} + +/*****************************************************************************/ +/* osl_terminateThread */ +/*****************************************************************************/ +void SAL_CALL osl_terminateThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + /* invalid arguments?*/ + if (pThreadImpl==0 || pThreadImpl->m_hThread==0) + { + /* assume thread is not running */ + return; + } + + osl_incrementInterlockedCount(&(pThreadImpl->m_nTerminationRequested)); +} + + +/*****************************************************************************/ +/* osl_scheduleThread */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread) +{ + osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; + + osl_yieldThread(); + + /* invalid arguments?*/ + if (pThreadImpl==0 || pThreadImpl->m_hThread==0) + { + /* assume thread is not running */ + return sal_False; + } + + return (sal_Bool)(0 == pThreadImpl->m_nTerminationRequested); +} + +/*****************************************************************************/ +/* osl_yieldThread */ +/*****************************************************************************/ +void SAL_CALL osl_yieldThread(void) +{ + Sleep(0); +} + +typedef struct _TLS +{ + DWORD dwIndex; + oslThreadKeyCallbackFunction pfnCallback; + struct _TLS *pNext, *pPrev; +} TLS, *PTLS; + +static PTLS g_pThreadKeyList = NULL; +CRITICAL_SECTION g_ThreadKeyListCS; + +static void AddKeyToList( PTLS pTls ) +{ + if ( pTls ) + { + EnterCriticalSection( &g_ThreadKeyListCS ); + + pTls->pNext = g_pThreadKeyList; + pTls->pPrev = 0; + + if ( g_pThreadKeyList ) + g_pThreadKeyList->pPrev = pTls; + + g_pThreadKeyList = pTls; + + LeaveCriticalSection( &g_ThreadKeyListCS ); + } +} + +static void RemoveKeyFromList( PTLS pTls ) +{ + if ( pTls ) + { + EnterCriticalSection( &g_ThreadKeyListCS ); + if ( pTls->pPrev ) + pTls->pPrev->pNext = pTls->pNext; + else + { + OSL_ASSERT( pTls == g_pThreadKeyList ); + g_pThreadKeyList = pTls->pNext; + } + + if ( pTls->pNext ) + pTls->pNext->pPrev = pTls->pPrev; + LeaveCriticalSection( &g_ThreadKeyListCS ); + } +} + +void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void) +{ + PTLS pTls; + + + EnterCriticalSection( &g_ThreadKeyListCS ); + pTls = g_pThreadKeyList; + while ( pTls ) + { + if ( pTls->pfnCallback ) + { + void *pValue = TlsGetValue( pTls->dwIndex ); + + if ( pValue ) + pTls->pfnCallback( pValue ); + } + + pTls = pTls->pNext; + } + LeaveCriticalSection( &g_ThreadKeyListCS ); +} + +/*****************************************************************************/ +/* osl_createThreadKey */ +/*****************************************************************************/ +oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback) +{ + PTLS pTls = rtl_allocateMemory( sizeof(TLS) ); + + if ( pTls ) + { + pTls->pfnCallback = pCallback; + if ( (DWORD)-1 == (pTls->dwIndex = TlsAlloc()) ) + { + rtl_freeMemory( pTls ); + pTls = 0; + } + else + AddKeyToList( pTls ); + } + + return ((oslThreadKey)pTls); +} + +/*****************************************************************************/ +/* osl_destroyThreadKey */ +/*****************************************************************************/ +void SAL_CALL osl_destroyThreadKey(oslThreadKey Key) +{ + if (Key != 0) + { + PTLS pTls = (PTLS)Key; + + RemoveKeyFromList( pTls ); + TlsFree( pTls->dwIndex ); + rtl_freeMemory( pTls ); + } +} + +/*****************************************************************************/ +/* osl_getThreadKeyData */ +/*****************************************************************************/ +void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key) +{ + if (Key != 0) + { + PTLS pTls = (PTLS)Key; + + return (TlsGetValue( pTls->dwIndex )); + } + + return (NULL); +} + +/*****************************************************************************/ +/* osl_setThreadKeyData */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData) +{ + if (Key != 0) + { + PTLS pTls = (PTLS)Key; + void* pOldData = NULL; + BOOL fSuccess; + + if ( pTls->pfnCallback ) + pOldData = TlsGetValue( pTls->dwIndex ); + + fSuccess = TlsSetValue( pTls->dwIndex, pData ); + + if ( fSuccess && pTls->pfnCallback && pOldData ) + pTls->pfnCallback( pOldData ); + + return (sal_Bool)(fSuccess != FALSE); + } + + return (sal_False); +} + + +/*****************************************************************************/ +/* osl_getThreadTextEncoding */ +/*****************************************************************************/ + +DWORD g_dwTLSTextEncodingIndex = (DWORD)-1; + + +rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void) +{ + DWORD dwEncoding; + rtl_TextEncoding _encoding; + BOOL gotACP; + + if ( (DWORD)-1 == g_dwTLSTextEncodingIndex ) + g_dwTLSTextEncodingIndex = TlsAlloc(); + + dwEncoding = (DWORD)TlsGetValue( g_dwTLSTextEncodingIndex ); + _encoding = LOWORD(dwEncoding); + gotACP = HIWORD(dwEncoding); + + + if ( !gotACP ) + { + char *pszEncoding; + + if ( NULL != (pszEncoding = getenv( "SOLAR_USER_RTL_TEXTENCODING" )) ) + _encoding = (rtl_TextEncoding)atoi(pszEncoding); + else + _encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() ); + + TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( _encoding, TRUE ) ); + } + + return _encoding; +} + +/*****************************************************************************/ +/* osl_getThreadTextEncoding */ +/*****************************************************************************/ +rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding ) +{ + rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding(); + + TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( Encoding, TRUE) ); + + return oldEncoding; +} + + + diff --git a/sal/osl/w32/time.c b/sal/osl/w32/time.c new file mode 100644 index 000000000000..a4d0b6fffbad --- /dev/null +++ b/sal/osl/w32/time.c @@ -0,0 +1,216 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/time.h> +#include <sys/timeb.h> + +extern sal_Bool TimeValueToFileTime(const TimeValue *cpTimeVal, FILETIME *pFTime); + +extern BOOL FileTimeToTimeValue( const FILETIME *cpFTime, TimeValue *pTimeVal ); + +//-------------------------------------------------- +// osl_getSystemTime +//-------------------------------------------------- + +sal_Bool SAL_CALL osl_getSystemTime(TimeValue* pTimeVal) +{ + SYSTEMTIME SystemTime; + FILETIME CurTime, OffTime; + __int64 Value; + + OSL_ASSERT(pTimeVal != 0); + + GetSystemTime(&SystemTime); + SystemTimeToFileTime(&SystemTime, &CurTime); + + SystemTime.wYear = 1970; + SystemTime.wMonth = 1; + SystemTime.wDayOfWeek = 0; + SystemTime.wDay = 1; + SystemTime.wHour = 0; + SystemTime.wMinute = 0; + SystemTime.wSecond = 0; + SystemTime.wMilliseconds = 0; + + SystemTimeToFileTime(&SystemTime, &OffTime); + + Value = *((__int64 *)&CurTime) - *((__int64 *)&OffTime); + + pTimeVal->Seconds = (unsigned long) (Value / 10000000L); + pTimeVal->Nanosec = (unsigned long)((Value % 10000000L) * 100); + + return (sal_True); +} + +//-------------------------------------------------- +// osl_getDateTimeFromTimeValue +//-------------------------------------------------- + +sal_Bool SAL_CALL osl_getDateTimeFromTimeValue( TimeValue* pTimeVal, oslDateTime* pDateTime ) +{ + FILETIME aFileTime; + SYSTEMTIME aSystemTime; + + if ( TimeValueToFileTime(pTimeVal, &aFileTime) ) + { + if ( FileTimeToSystemTime( &aFileTime, &aSystemTime ) ) + { + pDateTime->NanoSeconds = pTimeVal->Nanosec; + + pDateTime->Seconds = aSystemTime.wSecond; + pDateTime->Minutes = aSystemTime.wMinute; + pDateTime->Hours = aSystemTime.wHour; + pDateTime->Day = aSystemTime.wDay; + pDateTime->DayOfWeek = aSystemTime.wDayOfWeek; + pDateTime->Month = aSystemTime.wMonth; + pDateTime->Year = aSystemTime.wYear; + + return sal_True; + } + } + + return sal_False; +} + +//-------------------------------------------------- +// osl_getTimeValueFromDateTime +//-------------------------------------------------- + +sal_Bool SAL_CALL osl_getTimeValueFromDateTime( oslDateTime* pDateTime, TimeValue* pTimeVal ) +{ + FILETIME aFileTime; + SYSTEMTIME aSystemTime; + + aSystemTime.wMilliseconds = 0; + aSystemTime.wSecond = pDateTime->Seconds; + aSystemTime.wMinute = pDateTime->Minutes; + aSystemTime.wHour = pDateTime->Hours; + aSystemTime.wDay = pDateTime->Day; + aSystemTime.wDayOfWeek = pDateTime->DayOfWeek; + aSystemTime.wMonth = pDateTime->Month; + aSystemTime.wYear = pDateTime->Year; + + if ( SystemTimeToFileTime( &aSystemTime, &aFileTime ) ) + { + if (FileTimeToTimeValue( &aFileTime, pTimeVal ) ) + { + pTimeVal->Nanosec = pDateTime->NanoSeconds; + return sal_True; + } + } + + return sal_False; +} + + +//-------------------------------------------------- +// osl_getLocalTimeFromSystemTime +//-------------------------------------------------- + +sal_Bool SAL_CALL osl_getLocalTimeFromSystemTime( TimeValue* pSystemTimeVal, TimeValue* pLocalTimeVal ) +{ + TIME_ZONE_INFORMATION aTimeZoneInformation; + DWORD Success; + sal_Int64 bias; + + // get timezone information + if ( ( Success=GetTimeZoneInformation( &aTimeZoneInformation ) ) != TIME_ZONE_ID_INVALID) + { + bias=aTimeZoneInformation.Bias; + + // add bias for daylight saving time + if ( Success== TIME_ZONE_ID_DAYLIGHT ) + bias+=aTimeZoneInformation.DaylightBias; + + if ( (sal_Int64) pSystemTimeVal->Seconds > ( bias * 60 ) ) + { + pLocalTimeVal->Seconds = (sal_uInt32) (pSystemTimeVal->Seconds - ( bias * 60) ); + pLocalTimeVal->Nanosec = pSystemTimeVal->Nanosec; + + return sal_True; + } + } + + return sal_False; +} + +//-------------------------------------------------- +// osl_getSystemTimeFromLocalTime +//-------------------------------------------------- + +sal_Bool SAL_CALL osl_getSystemTimeFromLocalTime( TimeValue* pLocalTimeVal, TimeValue* pSystemTimeVal ) +{ + TIME_ZONE_INFORMATION aTimeZoneInformation; + DWORD Success; + sal_Int64 bias; + + // get timezone information + if ( ( Success=GetTimeZoneInformation( &aTimeZoneInformation ) ) != TIME_ZONE_ID_INVALID) + { + bias=aTimeZoneInformation.Bias; + + // add bias for daylight saving time + if ( Success== TIME_ZONE_ID_DAYLIGHT ) + bias+=aTimeZoneInformation.DaylightBias; + + if ( (sal_Int64) pLocalTimeVal->Seconds + ( bias * 60 ) > 0 ) + { + pSystemTimeVal->Seconds = (sal_uInt32) ( pLocalTimeVal->Seconds + ( bias * 60) ); + pSystemTimeVal->Nanosec = pLocalTimeVal->Nanosec; + + return sal_True; + } + } + + return sal_False; +} + + +static struct _timeb startTime; +static sal_Bool bGlobalTimer = sal_False; + +sal_uInt32 SAL_CALL osl_getGlobalTimer(void) +{ + struct _timeb currentTime; + sal_uInt32 nSeconds; + + if ( bGlobalTimer == sal_False ) + { + _ftime( &startTime ); + bGlobalTimer=sal_True; + } + + _ftime( ¤tTime ); + + nSeconds = (sal_uInt32)( currentTime.time - startTime.time ); + + return ( nSeconds * 1000 ) + (long)( currentTime.millitm - startTime.millitm ); +} + diff --git a/sal/osl/w32/util.c b/sal/osl/w32/util.c new file mode 100644 index 000000000000..f4d8cbf52d20 --- /dev/null +++ b/sal/osl/w32/util.c @@ -0,0 +1,37 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/util.h" + + + +extern sal_Bool SAL_CALL osl_getEthernetAddress( sal_uInt8 *pAddr ) +{ + pAddr = pAddr; /* avoid warnings */ + return sal_False; +} + |