diff options
Diffstat (limited to 'sal/osl/w32')
34 files changed, 16368 insertions, 0 deletions
diff --git a/sal/osl/w32/MAKEFILE.MK b/sal/osl/w32/MAKEFILE.MK new file mode 100644 index 000000000000..08e8745a9dcd --- /dev/null +++ b/sal/osl/w32/MAKEFILE.MK @@ -0,0 +1,114 @@ +#************************************************************************* +# +# 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 +ENABLE_EXCEPTIONS=TRUE +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)$/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)$/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)$/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..745c3317fbb2 --- /dev/null +++ b/sal/osl/w32/conditn.c @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/diagnose.c b/sal/osl/w32/diagnose.c new file mode 100755 index 000000000000..30356ee9af8c --- /dev/null +++ b/sal/osl/w32/diagnose.c @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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> + +#include "printtrace.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(); +} + +void osl_trace(char const * pszFormat, ...) { + va_list args; + va_start(args, pszFormat); + if ( IsDebuggerPresent() ) + { + sal_Char szMessage[512]; + int written = _vsnprintf( + szMessage, sizeof(szMessage) - 2, pszFormat, args ); + if ( written == -1 ) + written = sizeof(szMessage) - 2; + szMessage[ written++ ] = '\n'; + szMessage[ written ] = 0; + OutputDebugString( szMessage ); + } + printTrace((unsigned long) _getpid(), pszFormat, args); + 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; + + /* get app name or NULL if unknown (don't call assert) */ + LPCSTR lpszAppName = "Error"; + sal_Char szMessage[512]; + char const * env = getenv( "SAL_DIAGNOSE_ABORT" ); + + /* 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]; + int nCode; + + /* 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 */ + } + return ( ( env != NULL ) && ( *env != '\0' ) ); + } + + return sal_False; +#endif /* NO_DEBUG_CRT */ +} + +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); + + /* 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); + (void)nType; //unused, but part of public API/ABI + return nDisposition; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/dllentry.c b/sal/osl/w32/dllentry.c new file mode 100644 index 000000000000..4d894260446a --- /dev/null +++ b/sal/osl/w32/dllentry.c @@ -0,0 +1,358 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + +//------------------------------------------------------------------------------ +// DllMain +//------------------------------------------------------------------------------ +int osl_isSingleCPU = 0; + +#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 + + 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; + } + +#if OSL_DEBUG_LEVEL < 2 + /* Suppress file error messages from system like "Floppy A: not inserted" */ + SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS ); +#endif + + /* initialize global mutex */ + g_Mutex = osl_createMutex(); + + /* initialize "current directory" mutex */ + g_CurrentDirectoryMutex = osl_createMutex(); + + 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/file.cxx b/sal/osl/w32/file.cxx new file mode 100644 index 000000000000..b4648a72d2ae --- /dev/null +++ b/sal/osl/w32/file.cxx @@ -0,0 +1,1190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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, (SIZE_T) 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, (SIZE_T) 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); + + 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/file_dirvol.cxx b/sal/osl/w32/file_dirvol.cxx new file mode 100644 index 000000000000..b6dc0028879e --- /dev/null +++ b/sal/osl/w32/file_dirvol.cxx @@ -0,0 +1,1863 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 <sal/macros.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 + +//##################################################### +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), SAL_N_ELEMENTS(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; + + 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; + + 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; + + 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_FAIL( "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, SAL_N_ELEMENTS(vn))) + { + TCHAR vnfloppy[51]; + if (is_floppy_A_present() && + GetVolumeNameForVolumeMountPoint(FLOPPY_A, vnfloppy, SAL_N_ELEMENTS(vnfloppy)) && + (0 == wcscmp(vn, vnfloppy))) + return true; + + if (is_floppy_B_present() && + GetVolumeNameForVolumeMountPoint(FLOPPY_B, vnfloppy, SAL_N_ELEMENTS(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, SAL_N_ELEMENTS(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 = SAL_N_ELEMENTS(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 = SAL_N_ELEMENTS(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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/file_error.c b/sal/osl/w32/file_error.c new file mode 100644 index 000000000000..bc9048d72a36 --- /dev/null +++ b/sal/osl/w32/file_error.c @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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" +#include <sal/macros.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 = SAL_N_ELEMENTS(errtable); + + 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_FAIL( message ); +} +#endif /* OSL_DEBUG_LEVEL */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/file_error.h b/sal/osl/w32/file_error.h new file mode 100644 index 000000000000..f4ac71763c26 --- /dev/null +++ b/sal/osl/w32/file_error.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/file_url.cxx b/sal/osl/w32/file_url.cxx new file mode 100644 index 000000000000..75e9b98f0595 --- /dev/null +++ b/sal/osl/w32/file_url.cxx @@ -0,0 +1,1144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 <sal/macros.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 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 ( (dwFlags & VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD) || + 1 == lpCurrent - lpComponent ) + { + /* Either do allow periods anywhere, or current directory */ + lpComponentEnd = lpCurrent; + break; + } + else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent ) + { + /* Parent directory is O.K. */ + lpComponentEnd = lpCurrent; + break; + } + } + case 0: + case ' ': + if ( dwFlags & VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD ) + lpComponentEnd = lpCurrent; + else + { + 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), SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX_UNC) - 1, SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX_UNC) - 1 ) ) + { + /* This is long path in UNC notation */ + lpComponent = lpszPath + SAL_N_ELEMENTS(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), SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX) - 1, SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX) - 1 ) ) + { + /* This is long path */ + lpComponent = lpszPath + SAL_N_ELEMENTS(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 ) + { + dwPathType |= PATHTYPE_IS_SERVER; + } + 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 | VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD); + + 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 >= SAL_N_ELEMENTS(WSTR_SYSTEM_ROOT_PATH) ) + { + wcscpy( lpszLongPath, WSTR_SYSTEM_ROOT_PATH ); + return SAL_N_ELEMENTS(WSTR_SYSTEM_ROOT_PATH) - 1; + } + else + { + return SAL_N_ELEMENTS(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), SAL_N_ELEMENTS(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), SAL_N_ELEMENTS(WSTR_SYSTEM_ROOT_PATH) - 1, SAL_N_ELEMENTS(WSTR_SYSTEM_ROOT_PATH) - 1 ) + || 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL + nSkip, nDecodedLen - nSkip, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX), SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX) - 1, SAL_N_ELEMENTS(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), SAL_N_ELEMENTS( 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), SAL_N_ELEMENTS( 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 = SAL_N_ELEMENTS( 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 = SAL_N_ELEMENTS( 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_FAIL( "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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/file_url.h b/sal/osl/w32/file_url.h new file mode 100644 index 000000000000..3f12151442a9 --- /dev/null +++ b/sal/osl/w32/file_url.h @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD 0x0010 + +#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 */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/interlck.c b/sal/osl/w32/interlck.c new file mode 100644 index 000000000000..5c9e566a4a2d --- /dev/null +++ b/sal/osl/w32/interlck.c @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/module.cxx b/sal/osl/w32/module.cxx new file mode 100644 index 000000000000..70d4fa38a6ef --- /dev/null +++ b/sal/osl/w32/module.cxx @@ -0,0 +1,466 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* +* +* 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> +#include <vector> + +/* + 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; +#if OSL_DEBUG_LEVEL < 2 + UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); +#endif + rtl_uString* Module = NULL; + oslModule ret = 0; + oslFileError nError; + + RTL_LOGFILE_TRACE1( "{ osl_loadModule start: %S", (LPTSTR)&strModuleName->buffer ); + + OSL_ASSERT(strModuleName); + + 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); + + //In case of long path names (\\?\c:\...) try to shorten the filename. + //LoadLibrary cannot handle file names which exceed 260 letters. + //In case the path is to long, the function will fail. However, the error + //code can be different. For example, it returned ERROR_FILENAME_EXCED_RANGE + //on Windows XP and ERROR_INSUFFICIENT_BUFFER on Windows 7 (64bit) + if (hInstance == NULL && Module->length > 260) + { + std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > vec(Module->length + 1); + DWORD len = GetShortPathNameW(reinterpret_cast<LPCWSTR>(Module->buffer), + &vec[0], Module->length + 1); + if (len ) + { + hInstance = LoadLibraryW(&vec[0]); + + if (hInstance == NULL) + hInstance = LoadLibraryExW(&vec[0], NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); + } + } + + + if (hInstance <= (HINSTANCE)HINSTANCE_ERROR) + hInstance = 0; + + ret = (oslModule) hInstance; + rtl_uString_release(Module); +#if OSL_DEBUG_LEVEL < 2 + SetErrorMode(errorMode); +#endif + + RTL_LOGFILE_TRACE1( "} osl_loadModule end: %S", (LPTSTR)&strModuleName->buffer ); + + return ret; +} + +/*****************************************************************************/ +/* osl_loadModuleAscii */ +/*****************************************************************************/ +oslModule SAL_CALL osl_loadModuleAscii(const sal_Char *pModuleName, sal_Int32 nRtldMode ) +{ + (void) nRtldMode; /* avoid warnings */ + + HINSTANCE hInstance; + UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + oslModule ret = 0; + + RTL_LOGFILE_TRACE1( "{ osl_loadModule start: %s", pModuleName ); + + OSL_ASSERT(pModuleName); + + hInstance = LoadLibrary(pModuleName); + if (hInstance == NULL) + hInstance = LoadLibraryEx(pModuleName, NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); + + if (hInstance <= (HINSTANCE)HINSTANCE_ERROR) + hInstance = 0; + + ret = (oslModule) hInstance; + SetErrorMode(errorMode); + + RTL_LOGFILE_TRACE1( "} osl_loadModule end: %s", pModuleName ); + + 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 + +/***************************************************************************************/ +/* 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 +); + +/* 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 */ + return _osl_addressGetModuleURL_NT( pv, pustrURL ) || _osl_addressGetModuleURL_NT4( 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 +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/mutex.c b/sal/osl/w32/mutex.c new file mode 100644 index 000000000000..dad32bb8a1f9 --- /dev/null +++ b/sal/osl/w32/mutex.c @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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. +*/ + +/*****************************************************************************/ +/* osl_createMutex */ +/*****************************************************************************/ +oslMutex SAL_CALL osl_createMutex(void) +{ + CRITICAL_SECTION *pMutexImpl; + + pMutexImpl = calloc(sizeof(CRITICAL_SECTION), 1); + + OSL_ASSERT(pMutexImpl); /* alloc successful? */ + + InitializeCriticalSection(pMutexImpl); + + return (oslMutex)pMutexImpl; +} + +/*****************************************************************************/ +/* osl_destroyMutex */ +/*****************************************************************************/ +void SAL_CALL osl_destroyMutex(oslMutex Mutex) +{ + CRITICAL_SECTION *pMutexImpl = (CRITICAL_SECTION *)Mutex; + + if (pMutexImpl) + { + DeleteCriticalSection(pMutexImpl); + free(pMutexImpl); + } +} + +/*****************************************************************************/ +/* osl_acquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireMutex(oslMutex Mutex) +{ + CRITICAL_SECTION *pMutexImpl = (CRITICAL_SECTION *)Mutex; + + OSL_ASSERT(Mutex); + + EnterCriticalSection(pMutexImpl); + + return sal_True; +} + +/*****************************************************************************/ +/* osl_tryToAcquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireMutex(oslMutex Mutex) +{ + CRITICAL_SECTION *pMutexImpl = (CRITICAL_SECTION *)Mutex; + + OSL_ASSERT(Mutex); + + return (sal_Bool)(TryEnterCriticalSection(pMutexImpl) != FALSE); +} + +/*****************************************************************************/ +/* osl_releaseMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseMutex(oslMutex Mutex) +{ + CRITICAL_SECTION *pMutexImpl = (CRITICAL_SECTION *)Mutex; + + OSL_ASSERT(Mutex); + + LeaveCriticalSection(pMutexImpl); + + return sal_True; +} + +/*****************************************************************************/ +/* osl_getGlobalMutex */ +/*****************************************************************************/ + +/* initialized in dllentry.c */ +oslMutex g_Mutex; + +oslMutex * SAL_CALL osl_getGlobalMutex(void) +{ + return &g_Mutex; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/nlsupport.c b/sal/osl/w32/nlsupport.c new file mode 100644 index 000000000000..ea2b33e8e30d --- /dev/null +++ b/sal/osl/w32/nlsupport.c @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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"" ); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/path_helper.cxx b/sal/osl/w32/path_helper.cxx new file mode 100644 index 000000000000..aaf59f4ef586 --- /dev/null +++ b/sal/osl/w32/path_helper.cxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_CONSTASCII_USTRINGPARAM("\\")); +const rtl::OUString SLASH (RTL_CONSTASCII_USTRINGPARAM("/")); + +/******************************************************************* + 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; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/path_helper.h b/sal/osl/w32/path_helper.h new file mode 100644 index 000000000000..cb39c49e36d6 --- /dev/null +++ b/sal/osl/w32/path_helper.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/path_helper.hxx b/sal/osl/w32/path_helper.hxx new file mode 100644 index 000000000000..05fc117d25d8 --- /dev/null +++ b/sal/osl/w32/path_helper.hxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/pipe.c b/sal/osl/w32/pipe.c new file mode 100644 index 000000000000..9efe5e91e8b2 --- /dev/null +++ b/sal/osl/w32/pipe.c @@ -0,0 +1,526 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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/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 ( 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 ); + + pPipe->m_NamedObject = CreateMutexW( NULL, FALSE, name->buffer ); + + 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); + + /* 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 + { + CloseHandle( pPipe->m_NamedObject ); + pPipe->m_NamedObject = INVALID_HANDLE_VALUE; + } + } + } + else + { + 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 ); + } + + /* 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 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); + } + } +} + +/*****************************************************************************/ +/* osl_acceptPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe) +{ + oslPipe pAcceptedPipe = NULL; + + HANDLE Event; + OVERLAPPED os; + + DWORD nBytesTransfered; + rtl_uString* path = NULL; + rtl_uString* temp = NULL; + + OSL_ASSERT(pPipe); + + 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 ); + + return pAcceptedPipe; +} + +/*****************************************************************************/ +/* osl_receivePipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe, + void* pBuffer, + sal_Int32 BytesToRead) +{ + DWORD nBytes; + OVERLAPPED os; + + OSL_ASSERT(pPipe); + + 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; + } + } + + return (nBytes); +} + +/*****************************************************************************/ +/* osl_sendPipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe, + const void* pBuffer, + sal_Int32 BytesToSend) +{ + DWORD nBytes; + OVERLAPPED os; + + OSL_ASSERT(pPipe); + + 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; + } + + 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 occurred */ + sal_Int32 BytesSend= 0; + sal_Int32 BytesToSend= n; + + OSL_ASSERT(pPipe); + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend); + + /* error occurred? */ + 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 occurred */ + sal_Int32 BytesRead= 0; + sal_Int32 BytesToRead= n; + + OSL_ASSERT( pPipe ); + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead); + + /* error occurred? */ + 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); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/process.cxx b/sal/osl/w32/process.cxx new file mode 100644 index 000000000000..3fec90a8483a --- /dev/null +++ b/sal/osl/w32/process.cxx @@ -0,0 +1,658 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* +* +* 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" +#include <string.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; +} + +oslProcessError SAL_CALL osl_setEnvironment(rtl_uString *ustrVar, rtl_uString *ustrValue) +{ + LPCWSTR lpName = reinterpret_cast<LPCWSTR>(ustrVar->buffer); + LPCWSTR lpValue = reinterpret_cast<LPCWSTR>(ustrValue->buffer); + if (SetEnvironmentVariableW(lpName, lpValue)) + { + wchar_t *buffer = new wchar_t[wcslen(lpName) + 1 + wcslen(lpValue) + 1]; + wcscpy(buffer, lpName); + wcscat(buffer, L"="); + wcscat(buffer, lpValue); + _wputenv(buffer); + delete[] buffer; + return osl_Process_E_None; + } + return osl_Process_E_Unknown; +} + +oslProcessError SAL_CALL osl_clearEnvironment(rtl_uString *ustrVar) +{ + //If the second parameter is NULL, the variable is deleted from the current + //process's environment. + LPCWSTR lpName = reinterpret_cast<LPCWSTR>(ustrVar->buffer); + if (SetEnvironmentVariableW(lpName, NULL)) + { + wchar_t *buffer = new wchar_t[wcslen(lpName) + 1 + 1]; + wcscpy(buffer, lpName); + wcscat(buffer, L"="); + _wputenv(buffer); + delete[] buffer; + 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/procimpl.cxx b/sal/osl/w32/procimpl.cxx new file mode 100644 index 000000000000..54d5f912d0e2 --- /dev/null +++ b/sal/osl/w32/procimpl.cxx @@ -0,0 +1,644 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_CONSTASCII_USTRINGPARAM("COMSPEC")); +const rtl::OUString QUOTE(RTL_CONSTASCII_USTRINGPARAM("\"")); + +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(); + } + + //The parameter path must be a system path. If it is longer than 260 characters + //then it is shortened using the GetShortPathName function. This function only + //works if the path exists. Because "path" can be the path to an executable, it + //may not have the file extension ".exe". However, if the file on disk has the + //".exe" extension, then the function will fail. In this case a second attempt + //is started by adding the parameter "extension" to "path". + rtl::OUString getShortPath(rtl::OUString const & path, rtl::OUString const & extension) + { + rtl::OUString ret(path); + if (path.getLength() > 260) + { + std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > vec(path.getLength() + 1); + //GetShortPathNameW only works if the file can be found! + const DWORD len = GetShortPathNameW( + path.getStr(), &vec[0], path.getLength() + 1); + + if (!len && GetLastError() == ERROR_FILE_NOT_FOUND + && extension.getLength()) + { + const rtl::OUString extPath(path + extension); + std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > vec2( + extPath.getLength() + 1); + const DWORD len2 = GetShortPathNameW( + extPath.getStr(), &vec2[0], extPath.getLength() + 1); + ret = rtl::OUString(&vec2[0], len2); + } + else + { + ret = rtl::OUString(&vec[0], len); + } + } + return ret; + } + //########################################################## + // 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(); + + exe_path = getShortPath(exe_path, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".exe"))); + + 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 occurred 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/procimpl.h b/sal/osl/w32/procimpl.h new file mode 100644 index 000000000000..c4092a6c71a1 --- /dev/null +++ b/sal/osl/w32/procimpl.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/profile.cxx b/sal/osl/w32/profile.cxx new file mode 100644 index 000000000000..54b92684c31a --- /dev/null +++ b/sal/osl/w32/profile.cxx @@ -0,0 +1,2695 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* +* +* 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 <sal/macros.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) + { + 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); + + 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); + + 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; + + 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 < SAL_N_ELEMENTS(SubDirs); 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; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/salinit.cxx b/sal/osl/w32/salinit.cxx new file mode 100644 index 000000000000..ffe2c7e70132 --- /dev/null +++ b/sal/osl/w32/salinit.cxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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) +{ + // SetProcessDEPPolicy(PROCESS_DEP_ENABLE); + // SetDllDirectoryW(L""); + // SetSearchPathMode( + // BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT); + HMODULE h = GetModuleHandleW(L"kernel32.dll"); + if (h != 0) { + FARPROC p = GetProcAddress(h, "SetProcessDEPPolicy"); + if (p != 0) { + reinterpret_cast< BOOL (WINAPI *)(DWORD) >(p)(0x00000001); + } + p = GetProcAddress(h, "SetDllDirectoryW"); + if (p != 0) { + reinterpret_cast< BOOL (WINAPI *)(LPCWSTR) >(p)(L""); + } + p = GetProcAddress(h, "SetSearchPathMode"); + if (p != 0) { + reinterpret_cast< BOOL (WINAPI *)(DWORD) >(p)(0x8001); + } + } + + 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/secimpl.h b/sal/osl/w32/secimpl.h new file mode 100644 index 000000000000..1a3f5a6c834a --- /dev/null +++ b/sal/osl/w32/secimpl.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/security.c b/sal/osl/w32/security.c new file mode 100644 index 000000000000..56ca5623a08a --- /dev/null +++ b/sal/osl/w32/security.c @@ -0,0 +1,965 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 <sal/macros.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 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; + + 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) + { + 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) + { + UCHAR* pTmp = realloc(pInfoBuffer, nInfoBuffer); + if (pTmp) + pInfoBuffer = pTmp; + else + { + free(pInfoBuffer); + pInfoBuffer = NULL; + break; + } + } + 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 = SAL_N_ELEMENTS(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 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) + { + UCHAR* pTmp = realloc(pInfoBuffer, nInfoBuffer); + if (pTmp) + pInfoBuffer = pTmp; + else + { + free(pInfoBuffer); + pInfoBuffer = NULL; + break; + } + } + 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/semaphor.c b/sal/osl/w32/semaphor.c new file mode 100644 index 000000000000..41df50f478fa --- /dev/null +++ b/sal/osl/w32/semaphor.c @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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); +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/signal.cxx b/sal/osl/w32/signal.cxx new file mode 100644 index 000000000000..de2201f8d8a6 --- /dev/null +++ b/sal/osl/w32/signal.cxx @@ -0,0 +1,440 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* +* +* 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> +#include <sal/macros.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, SAL_N_ELEMENTS(szBuffer), + _T("%s -p %u -excp 0x%p -t %u%s"), + static_cast<sal_Char*>( 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/socket.cxx b/sal/osl/w32/socket.cxx new file mode 100644 index 000000000000..505507d61acf --- /dev/null +++ b/sal/osl/w32/socket.cxx @@ -0,0 +1,2176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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; + +/* + * __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 + (void)pImpl; +#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) +{ + OSL_ASSERT(Addr1); + OSL_ASSERT(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, pAddr2, 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 occurred */ + sal_uInt32 BytesRead= 0; + sal_uInt32 BytesToRead= n; + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receiveSocket(pSocket, + Ptr, + BytesToRead, + osl_Socket_MsgNormal); + + /* error occurred? */ + 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 occurred */ + 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 occurred? */ + 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); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/sockimpl.h b/sal/osl/w32/sockimpl.h new file mode 100644 index 000000000000..5887df981c4a --- /dev/null +++ b/sal/osl/w32/sockimpl.h @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/system.h b/sal/osl/w32/system.h new file mode 100644 index 000000000000..163d8232a35a --- /dev/null +++ b/sal/osl/w32/system.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/tempfile.cxx b/sal/osl/w32/tempfile.cxx new file mode 100644 index 000000000000..9922b699a932 --- /dev/null +++ b/sal/osl/w32/tempfile.cxx @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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> + +//##################################################### +// 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/thread.c b/sal/osl/w32/thread.c new file mode 100755 index 000000000000..02a67050083d --- /dev/null +++ b/sal/osl/w32/thread.c @@ -0,0 +1,620 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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); +} + +void SAL_CALL osl_setThreadName(char const * name) { +#ifdef _MSC_VER + /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */ +#pragma pack(push, 8) + struct { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + } info; +#pragma pack(pop) + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = (DWORD) -1; + info.dwFlags = 0; + __try { + RaiseException( + 0x406D1388, 0, sizeof info / sizeof (ULONG_PTR), + (ULONG_PTR *) &info); + } __except (EXCEPTION_EXECUTE_HANDLER) {} +#else + (void) name; +#endif +} + +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; +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/time.c b/sal/osl/w32/time.c new file mode 100644 index 000000000000..a60028b18e92 --- /dev/null +++ b/sal/osl/w32/time.c @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/util.c b/sal/osl/w32/util.c new file mode 100644 index 000000000000..08cda15ba0ef --- /dev/null +++ b/sal/osl/w32/util.c @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 ) +{ + (void)pAddr; //unused, but part of the API/ABI + return sal_False; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |