diff options
Diffstat (limited to 'sal/osl/unx')
45 files changed, 23540 insertions, 0 deletions
diff --git a/sal/osl/unx/asm/interlck_sparc.s b/sal/osl/unx/asm/interlck_sparc.s new file mode 100644 index 000000000000..a33e3539398e --- /dev/null +++ b/sal/osl/unx/asm/interlck_sparc.s @@ -0,0 +1,267 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/* + * Implements osl_[increment|decrement]InterlockedCount in two ways: + * sparcv8 architecture: use the "swap" instruction + * sparcv9/sparcv8plus architecture: use the "cas" instruction + * + * 32 bit mode with v8 and v8plus support: + * Initialize once with osl_InterlockedCountSetV9(int bv9) if you want to + * use the "cas" instruction, which is faster (no spinlock needed) + * Default is to use the "swap" instruction, which works on all supported + * SPARC cpu's + * + * osl_InterlockedCountSetV9(int bv9) + * bv9 = 0 use sparcv8 "swap" (spinlock) + * bv9 = 1 use sparcv9/sparcv8plus "cas" (no spinlock) + * + * 32 bit mode without v8 support (implies v8plus) or 64 bit mode: + * No need (nor the possibilty) to call osl_InterlockedCountSetV9(), + * sparcv9 mode is implied. Assemble with -xarch=v8plus (32 bit) or + * -xarch=v9 (64 bit). + * + */ + +#if !defined(__sparcv8plus) && !defined(__sparcv9) && !defined(__sparc_v9__) + +.section ".data" +.align 4 +osl_incrementInterLockCountFuncPtr: +.word osl_incrementInterlockedCountV8 +.type osl_incrementInterLockCountFuncPtr,#object +.size osl_incrementInterLockCountFuncPtr,4 + +.align 4 +osl_decrementInterLockCountFuncPtr: +.word osl_decrementInterlockedCountV8 +.type osl_decrementInterLockCountFuncPtr,#object +.size osl_decrementInterLockCountFuncPtr,4 + +.section ".text" + +#if defined(NETBSD) || defined(LINUX) +/* add the address of the calling "call" instruction (stored in %o7) to + * %o5 which contains _GLOBAL_OFFSET_TABLE_ + */ +.Laddoseven: + retl + add %o7, %o5, %o5 +#endif + + .global osl_incrementInterlockedCount + .align 4 + +osl_incrementInterlockedCount: + +#if defined(NETBSD) || defined(LINUX) + mov %o7, %g1 + sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %o5 + call .Laddoseven + add %o5, %lo(_GLOBAL_OFFSET_TABLE_+4), %o5 + mov %g1, %o7 +#endif + set osl_incrementInterLockCountFuncPtr, %o1 +#if defined(NETBSD) + ld [%o1 + %o5], %o1 +#endif + ld [%o1], %o1 + jmp %o1 + nop ! delay slot + .type osl_incrementInterlockedCount,#function + .size osl_incrementInterlockedCount,.-osl_incrementInterlockedCount + +.section ".text" + .global osl_decrementInterlockedCount + .align 4 + +osl_decrementInterlockedCount: + +#if defined(NETBSD) || defined(LINUX) + mov %o7, %g1 + sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %o5 + call .Laddoseven + add %o5, %lo(_GLOBAL_OFFSET_TABLE_+4), %o5 + mov %g1, %o7 +#endif + set osl_decrementInterLockCountFuncPtr, %o1 +#if defined(NETBSD) || defined(LINUX) + ld [%o1 + %o5], %o1 +#endif + ld [%o1], %o1 + jmp %o1 + nop ! delay slot + .type osl_decrementInterlockedCount,#function + .size osl_decrementInterlockedCount,.-osl_decrementInterlockedCount + +.section ".text" + .global osl_InterlockedCountSetV9 + .align 4 + +osl_InterlockedCountSetV9: + +#if defined(NETBSD) || defined(LINUX) + mov %o7, %g1 + sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %o5 + call .Laddoseven + add %o5, %lo(_GLOBAL_OFFSET_TABLE_+4), %o5 + mov %g1, %o7 +#endif + set osl_incrementInterLockCountFuncPtr, %o1 + set osl_decrementInterLockCountFuncPtr, %o2 + cmp %o0, %g0 + bnz 1f + nop ! delay slot + set osl_incrementInterlockedCountV8, %o0 + set osl_decrementInterlockedCountV8, %o3 +#if defined(NETBSD) || defined(LINUX) + ld [%o0 + %o5], %o0 + ld [%o1 + %o5], %o1 + ld [%o2 + %o5], %o2 + ld [%o3 + %o5], %o3 +#endif + st %o3,[%o2] + retl + st %o0,[%o1] +1: set osl_incrementInterlockedCountV9, %o0 + set osl_decrementInterlockedCountV9, %o3 +#if defined(NETBSD) || defined(LINUX) + ld [%o0 + %o5], %o0 + ld [%o1 + %o5], %o1 + ld [%o2 + %o5], %o2 + ld [%o3 + %o5], %o3 +#endif + st %o3,[%o2] + retl + st %o0,[%o1] + + .type osl_InterlockedCountSetV9,#function + .size osl_InterlockedCountSetV9,.-osl_InterlockedCountSetV9 + + +.section ".text" + .local osl_incrementInterlockedCountV8 + .align 4 + +! Implements osl_[increment|decrement]InterlockedCount with sparcv8 "swap" instruction. +! Uses -4096 as lock value for spinlock to allow for small negative counts. + +osl_incrementInterlockedCountV8: + +1: ld [%o0], %o1 + cmp %o1, -4096 ! test spinlock + be 1b + mov -4096, %o1 ! delay slot + swap [%o0], %o1 + cmp %o1, -4096 + be 1b + inc %o1 ! delay slot, if we got spinlock, increment count + st %o1, [%o0] + retl + mov %o1, %o0 ! delay slot + + .type osl_incrementInterlockedCountV8,#function + .size osl_incrementInterlockedCountV8,.-osl_incrementInterlockedCountV8 + + +.section ".text" + .local osl_decrementInterlockedCountV8 + .align 4 + +osl_decrementInterlockedCountV8: + +1: ld [%o0], %o1 + cmp %o1, -4096 ! test spinlock + be 1b + mov -4096, %o1 ! delay slot + swap [%o0], %o1 + cmp %o1, -4096 + be 1b + dec %o1 ! delay slot, if we got spinlock, decrement count + st %o1, [%o0] ! delay slot + retl + mov %o1, %o0 ! delay slot + + .type osl_decrementInterlockedCountV8,#function + .size osl_decrementInterlockedCountV8,.-osl_decrementInterlockedCountV8 + +#endif /* !__sparcv8plus && !__sparcv9 && !_sparcv9__ */ + +.section ".text" +#if defined(__sparcv8plus) || defined(__sparcv9) || defined(__sparc_v9__) +#define osl_incrementInterlockedCountV9 osl_incrementInterlockedCount + .global osl_incrementInterlockedCountV9 +#else + .local osl_incrementInterlockedCountV9 +#endif + .align 8 + +! Implements osl_[increment|decrement]InterlockedCount with sparcv9(sparcv8plus) "cas" +! instruction. + +osl_incrementInterlockedCountV9: + +1: ld [%o0], %o1 + add %o1, 1, %o2 +! allow linux to build for v8 + .word 0xD5E21009 +! cas [%o0], %o1, %o2 + cmp %o1, %o2 + bne 1b + nop ! delay slot + retl + add %o2, 1, %o0 ! delay slot + + .type osl_incrementInterlockedCountV9,#function + .size osl_incrementInterlockedCountV9,.-osl_incrementInterlockedCountV9 + + +.section ".text" +#if defined(__sparcv8plus) || defined(__sparcv9) || defined(__sparc_v9__) +#define osl_decrementInterlockedCountV9 osl_decrementInterlockedCount + .global osl_decrementInterlockedCountV9 +#else + .local osl_decrementInterlockedCountV9 +#endif + .align 8 + +osl_decrementInterlockedCountV9: + +1: ld [%o0], %o1 + sub %o1, 1, %o2 +! allow linux to build for v8 + .word 0xD5E21009 +! cas [%o0], %o1, %o2 + cmp %o1, %o2 + bne 1b + nop ! delay slot + retl + sub %o2, 1, %o0 ! delay slot + + .type osl_decrementInterlockedCountV9,#function + .size osl_decrementInterlockedCountV9,.-osl_decrementInterlockedCountV9 diff --git a/sal/osl/unx/asm/interlck_x86.s b/sal/osl/unx/asm/interlck_x86.s new file mode 100644 index 000000000000..c1f99008d406 --- /dev/null +++ b/sal/osl/unx/asm/interlck_x86.s @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +.section .text,"ax" + .globl osl_incrementInterlockedCount + +osl_incrementInterlockedCount: + + push %ebp + mov %esp,%ebp + push %ebx + call 1f +1: + pop %ebx + add $_GLOBAL_OFFSET_TABLE_+0x1,%ebx + mov 8(%ebp),%ecx + mov $1,%eax + mov osl_isSingleCPU@GOT(%ebx),%edx + cmp $0,(%edx) + je 2f + xadd %eax,(%ecx) + jmp 3f +2: + lock + xadd %eax,(%ecx) +3: + inc %eax + pop %ebx + mov %ebp,%esp + pop %ebp + ret + + .type osl_incrementInterlockedCount,@function + .size osl_incrementInterlockedCount,.-osl_incrementInterlockedCount + +.section .text,"ax" + .globl osl_decrementInterlockedCount + +osl_decrementInterlockedCount: + + push %ebp + mov %esp,%ebp + push %ebx + call 1f +1: + pop %ebx + add $_GLOBAL_OFFSET_TABLE_+0x1,%ebx + mov 8(%ebp),%ecx + orl $-1,%eax + mov osl_isSingleCPU@GOT(%ebx),%edx + cmp $0,(%edx) + je 2f + xadd %eax,(%ecx) + jmp 3f +2: + lock + xadd %eax,(%ecx) +3: + dec %eax + pop %ebx + mov %ebp,%esp + pop %ebp + ret + + .type osl_decrementInterlockedCount,@function + .size osl_decrementInterlockedCount,.-osl_decrementInterlockedCount + diff --git a/sal/osl/unx/backtrace.c b/sal/osl/unx/backtrace.c new file mode 100755 index 000000000000..00156b80f1d6 --- /dev/null +++ b/sal/osl/unx/backtrace.c @@ -0,0 +1,359 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#ifdef SOLARIS + +#include <dlfcn.h> +#include <pthread.h> +#include <setjmp.h> +#include <stdio.h> +#include <sys/frame.h> +#include "backtrace.h" + +#if defined(SPARC) + +#if defined IS_LP64 + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0x7ff + +#else + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0 + +#endif + +#elif defined( INTEL ) + +#define FRAME_PTR_OFFSET 3 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0 + +#else + +#error Unknown Solaris target platform. + +#endif /* defined SPARC or INTEL */ + + +int backtrace( void **buffer, int max_frames ) +{ + jmp_buf ctx; + long fpval; + struct frame *fp; + int i; + + /* flush register windows */ +#ifdef SPARC + asm("ta 3"); +#endif + + /* get stack- and framepointer */ + setjmp(ctx); + + fpval = ((long*)(ctx))[FRAME_PTR_OFFSET]; + fp = (struct frame*)((char*)(fpval) + STACK_BIAS); + + for (i = 0; (i < FRAME_OFFSET) && (fp != 0); i++) + fp = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); + + /* iterate through backtrace */ + for (i = 0; (fp != 0) && (fp->fr_savpc != 0) && (i < max_frames); i++) + { + /* saved (prev) frame */ + struct frame * prev = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); + + /* store frame */ + *(buffer++) = (void*)(fp->fr_savpc); + + /* prev frame (w/ stack growing top down) */ + fp = (prev > fp) ? prev : 0; + } + + /* return number of frames stored */ + return i; +} + +void backtrace_symbols_fd( void **buffer, int size, int fd ) +{ + FILE *fp = fdopen( fd, "w" ); + + if ( fp ) + { + void **pFramePtr; + + for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- ) + { + Dl_info dli; + ptrdiff_t offset; + + if ( 0 != dladdr( *pFramePtr, &dli ) ) + { + if ( dli.dli_fname && dli.dli_fbase ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase; + fprintf( fp, "%s+0x%x", dli.dli_fname, offset ); + } + if ( dli.dli_sname && dli.dli_saddr ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr; + fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset ); + } + } + fprintf( fp, "[0x%x]\n", *pFramePtr ); + } + + fflush( fp ); + fclose( fp ); + } +} + +#endif /* defined SOLARIS */ + + +#if defined FREEBSD || defined NETBSD +#include <dlfcn.h> +#include <pthread.h> +#include <setjmp.h> +#include <stddef.h> +#include <stdio.h> +#include "backtrace.h" + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 + +int backtrace( void **buffer, int max_frames ) +{ + struct frame *fp; + jmp_buf ctx; + int i; + /* get stack- and framepointer */ + setjmp(ctx); + fp = (struct frame*)(((size_t*)(ctx))[FRAME_PTR_OFFSET]); + for ( i=0; (i<FRAME_OFFSET) && (fp!=0); i++) + fp = fp->fr_savfp; + /* iterate through backtrace */ + for (i=0; fp && fp->fr_savpc && i<max_frames; i++) + { + /* store frame */ + *(buffer++) = (void *)fp->fr_savpc; + /* next frame */ + fp=fp->fr_savfp; + } + return i; +} + +void backtrace_symbols_fd( void **buffer, int size, int fd ) +{ + FILE *fp = fdopen( fd, "w" ); + + if ( fp ) + { + void **pFramePtr; + for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- ) + { + Dl_info dli; + ptrdiff_t offset; + + if ( 0 != dladdr( *pFramePtr, &dli ) ) + { + if ( dli.dli_fname && dli.dli_fbase ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase; + fprintf( fp, "%s+0x%x", dli.dli_fname, offset ); + } + if ( dli.dli_sname && dli.dli_saddr ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr; + fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset ); + } + } + fprintf( fp, "[0x%x]\n", *pFramePtr ); + } + fflush( fp ); + fclose( fp ); + } +} +#endif /* defined FREEBSD */ + +#ifdef LINUX + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <dlfcn.h> +#include <pthread.h> +#include <setjmp.h> +#include <stdio.h> +#include "backtrace.h" + +#if defined(SPARC) + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 + +#else + +#error Unknown Linux target platform. + +#endif /* defined SPARC or INTEL */ + +typedef int ptrdiff_t; + +int backtrace( void **buffer, int max_frames ) +{ + struct frame *fp; + jmp_buf ctx; + int i; + + /* flush register windows */ +#ifdef SPARC + asm("ta 3"); +#endif + /* get stack- and framepointer */ + setjmp(ctx); + fp = (struct frame*)(((size_t*)(ctx))[FRAME_PTR_OFFSET]); + for ( i=0; (i<FRAME_OFFSET) && (fp!=0); i++) + fp = fp->fr_savfp; + + /* iterate through backtrace */ + for (i=0; fp && fp->fr_savpc && i<max_frames; i++) + { + /* store frame */ + *(buffer++) = (void *)fp->fr_savpc; + /* next frame */ + fp=fp->fr_savfp; + } + return i; +} + +void backtrace_symbols_fd( void **buffer, int size, int fd ) +{ + FILE *fp = fdopen( fd, "w" ); + + if ( fp ) + { + void **pFramePtr; + + for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- ) + { + Dl_info dli; + ptrdiff_t offset; + + if ( 0 != dladdr( *pFramePtr, &dli ) ) + { + if ( dli.dli_fname && dli.dli_fbase ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase; + fprintf( fp, "%s+0x%x", dli.dli_fname, offset ); + } + if ( dli.dli_sname && dli.dli_saddr ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr; + fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset ); + } + } + fprintf( fp, "[0x%x]\n", *pFramePtr ); + } + + fflush( fp ); + fclose( fp ); + } +} + +#endif /* defined LINUX */ + +#if defined( MACOSX ) + +#include <dlfcn.h> +#include <stdio.h> +#include "backtrace.h" + +typedef unsigned ptrdiff_t; + +/* glib backtrace is only available on MacOsX 10.5 or higher + so we do it on our own */ + +int backtrace( void **buffer, int max_frames ) +{ + void **frame = (void **)__builtin_frame_address(0); + void **bp = ( void **)(*frame); + void *ip = frame[1]; + int i; + + for ( i = 0; bp && ip && i < max_frames; i++ ) + { + *(buffer++) = ip; + + ip = bp[1]; + bp = (void**)(bp[0]); + } + + return i; +} + + +void backtrace_symbols_fd( void **buffer, int size, int fd ) +{ + FILE *fp = fdopen( fd, "w" ); + + if ( fp ) + { + void **pFramePtr; + + for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- ) + { + Dl_info dli; + ptrdiff_t offset; + + if ( 0 != dladdr( *pFramePtr, &dli ) ) + { + if ( dli.dli_fname && dli.dli_fbase ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase; + fprintf( fp, "%s+0x%x", dli.dli_fname, offset ); + } + if ( dli.dli_sname && dli.dli_saddr ) + { + offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr; + fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset ); + } + } + fprintf( fp, "[0x%x]\n", (unsigned int)*pFramePtr ); + } + + fflush( fp ); + fclose( fp ); + } +} + +#endif /* defined MACOSX */ diff --git a/sal/osl/unx/backtrace.h b/sal/osl/unx/backtrace.h new file mode 100755 index 000000000000..1ca2ae84c4a0 --- /dev/null +++ b/sal/osl/unx/backtrace.h @@ -0,0 +1,99 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#if defined (SOLARIS) || (FREEBSD) + +#ifdef __cplusplus +extern "C" { +#endif + +/* backtrace function with same behaviour as defined in GNU libc */ + +int backtrace( void **buffer, int max_frames ); + +void backtrace_symbols_fd( void **buffer, int size, int fd ); + +/* no frame.h on FreeBSD */ +#if defined FREEBSD +struct frame { + long arg0[8]; + long arg1[6]; + struct frame *fr_savfp; + long fr_savpc; +}; +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined SOLARIS || FREEBSD */ + +#if defined (LINUX) && defined (SPARC) +#ifdef __cplusplus +extern "C" { +#endif + +/* backtrace function with same behaviour as defined in GNU libc */ + +int backtrace( void **buffer, int max_frames ); + +void backtrace_symbols_fd( void **buffer, int size, int fd ); + +/* no frame.h on linux sparc */ +struct frame { + long arg0[8]; + long arg1[6]; + struct frame *fr_savfp; + long fr_savpc; +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined LINUX && SPARC */ + +#if defined (MACOSX) + +#ifdef __cplusplus +extern "C" { +#endif + +/* backtrace function with same behaviour as defined in GNU libc */ + +int backtrace( void **buffer, int max_frames ); + +void backtrace_symbols_fd( void **buffer, int size, int fd ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined MACOSX */ diff --git a/sal/osl/unx/conditn.c b/sal/osl/unx/conditn.c new file mode 100644 index 000000000000..ea701d221e55 --- /dev/null +++ b/sal/osl/unx/conditn.c @@ -0,0 +1,350 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" +#include <sal/types.h> + +#include <osl/conditn.h> +#include <osl/diagnose.h> +#include <osl/time.h> + + +typedef struct _oslConditionImpl +{ + pthread_cond_t m_Condition; + pthread_mutex_t m_Lock; + sal_Bool m_State; +} oslConditionImpl; + + +/*****************************************************************************/ +/* osl_createCondition */ +/*****************************************************************************/ +oslCondition SAL_CALL osl_createCondition() +{ + oslConditionImpl* pCond; + int nRet=0; + + pCond = (oslConditionImpl*) malloc(sizeof(oslConditionImpl)); + + OSL_ASSERT(pCond); + + if ( pCond == 0 ) + { + return 0; + } + + pCond->m_State = sal_False; + + /* init condition variable with default attr. (PTHREAD_PROCESS_PRIVAT) */ + nRet = pthread_cond_init(&pCond->m_Condition, PTHREAD_CONDATTR_DEFAULT); + if ( nRet != 0 ) + { + OSL_TRACE("osl_createCondition : condition init failed. Errno: %d; '%s'\n", + nRet, strerror(nRet)); + + free(pCond); + return 0; + } + + nRet = pthread_mutex_init(&pCond->m_Lock, PTHREAD_MUTEXATTR_DEFAULT); + if ( nRet != 0 ) + { + OSL_TRACE("osl_createCondition : mutex init failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + + nRet = pthread_cond_destroy(&pCond->m_Condition); + if ( nRet != 0 ) + { + OSL_TRACE("osl_createCondition : destroy condition failed. Errno: %d; '%s'\n", + nRet, strerror(nRet)); + } + + free(pCond); + pCond = 0; + } + + return (oslCondition)pCond; +} + +/*****************************************************************************/ +/* osl_destroyCondition */ +/*****************************************************************************/ +void SAL_CALL osl_destroyCondition(oslCondition Condition) +{ + oslConditionImpl* pCond; + int nRet = 0; + + if ( Condition ) + { + pCond = (oslConditionImpl*)Condition; + + nRet = pthread_cond_destroy(&pCond->m_Condition); + if ( nRet != 0 ) + { + OSL_TRACE("osl_destroyCondition : destroy condition failed. Errno: %d; '%s'\n", + nRet, strerror(nRet)); + } + nRet = pthread_mutex_destroy(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_destroyCondition : destroy mutex failed. Errno: %d; '%s'\n", + nRet, strerror(nRet)); + } + + free(Condition); + } + + return; +} + +/*****************************************************************************/ +/* osl_setCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setCondition(oslCondition Condition) +{ + oslConditionImpl* pCond; + int nRet=0; + + OSL_ASSERT(Condition); + pCond = (oslConditionImpl*)Condition; + + if ( pCond == 0 ) + { + return sal_False; + } + + nRet = pthread_mutex_lock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_setCondition : mutex lock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + pCond->m_State = sal_True; + nRet = pthread_cond_broadcast(&pCond->m_Condition); + if ( nRet != 0 ) + { + OSL_TRACE("osl_setCondition : condition broadcast failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_setCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + return sal_True; + +} + +/*****************************************************************************/ +/* osl_resetCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_resetCondition(oslCondition Condition) +{ + oslConditionImpl* pCond; + int nRet=0; + + OSL_ASSERT(Condition); + + pCond = (oslConditionImpl*)Condition; + + if ( pCond == 0 ) + { + return sal_False; + } + + nRet = pthread_mutex_lock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_resetCondition : mutex lock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + pCond->m_State = sal_False; + + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_resetCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + return sal_True; +} + +/*****************************************************************************/ +/* osl_waitCondition */ +/*****************************************************************************/ +oslConditionResult SAL_CALL osl_waitCondition(oslCondition Condition, const TimeValue* pTimeout) +{ + oslConditionImpl* pCond; + int nRet=0; + oslConditionResult Result = osl_cond_result_ok; + + OSL_ASSERT(Condition); + pCond = (oslConditionImpl*)Condition; + + if ( pCond == 0 ) + { + return osl_cond_result_error; + } + + nRet = pthread_mutex_lock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : mutex lock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return osl_cond_result_error; + } + + if ( pTimeout ) + { + if ( ! pCond->m_State ) + { + int ret; + struct timeval tp; + struct timespec to; + + gettimeofday(&tp, NULL); + + SET_TIMESPEC( to, tp.tv_sec + pTimeout->Seconds, + tp.tv_usec * 1000 + pTimeout->Nanosec ); + + /* spurious wake up prevention */ + do + { + ret = pthread_cond_timedwait(&pCond->m_Condition, &pCond->m_Lock, &to); + if ( ret != 0 ) + { + if ( ret == ETIME || ret == ETIMEDOUT ) + { + Result = osl_cond_result_timeout; + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if (nRet != 0) + { + OSL_TRACE("osl_waitCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + return Result; + } + else if ( ret != EINTR ) + { + Result = osl_cond_result_error; + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + return Result; + } +/* OSL_TRACE("EINTR\n");*/ + } + } + while ( !pCond->m_State ); + } + } + else + { + while ( !pCond->m_State ) + { + nRet = pthread_cond_wait(&pCond->m_Condition, &pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : condition wait failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + Result = osl_cond_result_error; + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + return Result; + } + } + } + + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_waitCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + return Result; +} + +/*****************************************************************************/ +/* osl_checkCondition */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_checkCondition(oslCondition Condition) +{ + sal_Bool State; + oslConditionImpl* pCond; + int nRet=0; + + OSL_ASSERT(Condition); + pCond = (oslConditionImpl*)Condition; + + if ( pCond == 0 ) + { + return sal_False; + } + + nRet = pthread_mutex_lock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_checkCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + State = pCond->m_State; + + nRet = pthread_mutex_unlock(&pCond->m_Lock); + if ( nRet != 0 ) + { + OSL_TRACE("osl_checkCondition : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + return State; +} + + diff --git a/sal/osl/unx/diagnose.c b/sal/osl/unx/diagnose.c new file mode 100644 index 000000000000..bb8cbca406bd --- /dev/null +++ b/sal/osl/unx/diagnose.c @@ -0,0 +1,332 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/diagnose.h" +#include "system.h" + + +#ifndef HAVE_DLFCN_H + +#if defined(LINUX) || defined(SOLARIS) +#define HAVE_DLFCN_H +#endif /* LINUX || SOLARIS */ + +#endif /* HAVE_DLFCN_H */ + + +#ifdef HAVE_DLFCN_H + +#ifndef INCLUDED_DLFCN_H +#include <dlfcn.h> +#define INCLUDED_DLFCN_H +#endif + +#endif /* HAVE_DLFCN_H */ +#include "osl/thread.h" + +#ifndef INCLUDED_PTHREAD_H +#include <pthread.h> +#define INCLUDED_PTHREAD_H +#endif + +#ifndef INCLUDED_STDDEF_H +#include <stddef.h> +#define INCLUDED_STDDEF_H +#endif + +/************************************************************************/ +/* Internal data structures and functions */ +/************************************************************************/ + +static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; + +typedef pfunc_osl_printDebugMessage oslDebugMessageFunc; +static oslDebugMessageFunc volatile g_pDebugMessageFunc = 0; + +typedef pfunc_osl_printDetailedDebugMessage oslDetailedDebugMessageFunc; +static oslDetailedDebugMessageFunc volatile g_pDetailedDebugMessageFunc = 0; + +static void osl_diagnose_backtrace_Impl ( + oslDebugMessageFunc f); + +#define OSL_DIAGNOSE_OUTPUTMESSAGE(f, s) \ +((f != 0) ? (*(f))((s)) : (void)fprintf(stderr, "%s", (s))) + +#if defined (LINUX) || defined (SOLARIS) +/************************************************************************/ +/* osl_diagnose_frame_Impl */ +/************************************************************************/ +static void osl_diagnose_frame_Impl ( + oslDebugMessageFunc f, + int depth, + void * pc) +{ + const char *fname = 0, *sname = 0; + void *fbase = 0, *saddr = 0; + ptrdiff_t offset; + char szMessage[1024]; + +#ifdef INCLUDED_DLFCN_H + Dl_info dli; + if (dladdr (pc, &dli) != 0) + { + fname = dli.dli_fname; + fbase = dli.dli_fbase; + sname = dli.dli_sname; + saddr = dli.dli_saddr; + } +#endif /* INCLUDED_DLFCN_H */ + + if (saddr) + offset = (ptrdiff_t)(pc) - (ptrdiff_t)(saddr); + else if (fbase) + offset = (ptrdiff_t)(pc) - (ptrdiff_t)(fbase); + else + offset = (ptrdiff_t)(pc); + + snprintf (szMessage, sizeof(szMessage), + "Backtrace: [%d] %s: %s+0x%" SAL_PRI_PTRDIFFT "x\n", + depth, + fname ? fname : "<unknown>", + sname ? sname : "???", + offset); + + OSL_DIAGNOSE_OUTPUTMESSAGE(f, szMessage); +} +#endif + +/************************************************************************/ +/* osl_diagnose_backtrace_Impl */ +/************************************************************************/ +#if defined(LINUX) + +#include <execinfo.h> + +#define FRAME_COUNT 64 +#define FRAME_OFFSET 1 + +static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) +{ + void * ppFrames[FRAME_COUNT]; + int i, n; + + n = backtrace (ppFrames, FRAME_COUNT); + for (i = FRAME_OFFSET; i < n; i++) + { + osl_diagnose_frame_Impl (f, (i - FRAME_OFFSET), ppFrames[i]); + } +} + +#elif defined(SOLARIS) + +#include <pthread.h> +#include <setjmp.h> +#include <sys/frame.h> + +#if defined(SPARC) + +#if defined IS_LP64 + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0x7ff + +#else + +#define FRAME_PTR_OFFSET 1 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0 + +#endif + +#elif defined(INTEL) + +#define FRAME_PTR_OFFSET 3 +#define FRAME_OFFSET 0 +#define STACK_BIAS 0 + +#endif /* (SPARC || INTEL) */ + +static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) +{ + jmp_buf ctx; + long fpval; + struct frame * fp; + int i; + +#if defined(SPARC) + asm("ta 3"); +#endif /* SPARC */ + setjmp (ctx); + + fpval = ((long*)(ctx))[FRAME_PTR_OFFSET]; + fp = (struct frame*)((char*)(fpval) + STACK_BIAS); + + for (i = 0; (i < FRAME_OFFSET) && (fp != 0); i++) + fp = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); + + for (i = 0; (fp != 0) && (fp->fr_savpc != 0); i++) + { + struct frame * prev = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); + osl_diagnose_frame_Impl (f, i, (void*)(fp->fr_savpc)); + fp = (prev > fp) ? prev : 0; + } +} + +#else /* (LINUX || SOLARIS) */ + +static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) +{ + /* not yet implemented */ +} + +#endif /* (LINUX || SOLARIS) */ + +/************************************************************************/ +/* osl_assertFailedLine */ +/************************************************************************/ +sal_Bool SAL_CALL osl_assertFailedLine ( + const sal_Char* pszFileName, + sal_Int32 nLine, + const sal_Char* pszMessage) +{ + oslDebugMessageFunc f = g_pDebugMessageFunc; + char szMessage[1024]; + + /* If there's a callback for detailed messages, use it */ + if ( g_pDetailedDebugMessageFunc != NULL ) + { + g_pDetailedDebugMessageFunc( pszFileName, nLine, pszMessage ); + return sal_False; + } + + /* if SAL assertions are disabled in general, stop here */ + if ( getenv("DISABLE_SAL_DBGBOX") ) + return sal_False; + + /* format message into buffer */ + if (pszMessage != 0) + { + snprintf(szMessage, sizeof(szMessage), + "Error: File %s, Line %" SAL_PRIdINT32 ": %s\n", + pszFileName, nLine, pszMessage); + } + else + { + snprintf(szMessage, sizeof(szMessage), + "Error: File %s, Line %" SAL_PRIdINT32 "\n", + pszFileName, nLine); + } + + /* acquire lock to serialize output message(s) */ + pthread_mutex_lock(&g_mutex); + + /* output message buffer */ + OSL_DIAGNOSE_OUTPUTMESSAGE(f, szMessage); + + /* output backtrace */ + osl_diagnose_backtrace_Impl(f); + + /* release lock and leave, w/o calling osl_breakDebug() */ + pthread_mutex_unlock(&g_mutex); + return sal_False; +} + +/************************************************************************/ +/* osl_breakDebug */ +/************************************************************************/ +void SAL_CALL osl_breakDebug() +{ + exit(0); +} + +/************************************************************************/ +/* osl_reportError */ +/************************************************************************/ +sal_Int32 SAL_CALL osl_reportError ( + sal_uInt32 nType, + const sal_Char* pszMessage) +{ + (void) nType; /* unused */ + fputs(pszMessage, stderr); + return 0; +} + +/************************************************************************/ +/* osl_setDebugMessageFunc */ +/************************************************************************/ +oslDebugMessageFunc SAL_CALL osl_setDebugMessageFunc ( + oslDebugMessageFunc pNewFunc) +{ + oslDebugMessageFunc pOldFunc = g_pDebugMessageFunc; + g_pDebugMessageFunc = pNewFunc; + return pOldFunc; +} + +/************************************************************************/ +/* osl_setDetailedDebugMessageFunc */ +/************************************************************************/ +pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc ( + pfunc_osl_printDetailedDebugMessage pNewFunc) +{ + oslDetailedDebugMessageFunc pOldFunc = g_pDetailedDebugMessageFunc; + g_pDetailedDebugMessageFunc = pNewFunc; + return pOldFunc; +} + +/************************************************************************/ +/* osl_trace */ +/************************************************************************/ +/* comment this define to stop output thread identifier*/ +#define OSL_TRACE_THREAD 1 +void SAL_CALL osl_trace ( + const sal_Char* lpszFormat, ...) +{ + va_list args; + +#if defined(OSL_PROFILING) + fprintf(stderr, "Time: %06lu : ", osl_getGlobalTimer() ); +#else +#if defined(OSL_TRACE_THREAD) + fprintf( + stderr, "Thread: %6lu :", + SAL_INT_CAST(unsigned long, osl_getThreadIdentifier(NULL))); +#else + fprintf(stderr, "Trace Message: "); +#endif +#endif + + va_start(args, lpszFormat); + vfprintf(stderr, lpszFormat, args); + va_end(args); + + fprintf(stderr,"\n"); + fflush(stderr); +} + +/************************************************************************/ + diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx new file mode 100644 index 000000000000..cc0c041bc328 --- /dev/null +++ b/sal/osl/unx/file.cxx @@ -0,0 +1,1397 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "osl/file.hxx" + +#include "osl/diagnose.h" +#include "rtl/alloc.h" + +#include "system.h" +#include "file_error_transl.h" +#include "file_url.h" + +#include <algorithm> +#include <limits> + +#include <string.h> +#include <pthread.h> +#include <sys/mman.h> + +#if defined(MACOSX) + +#include <sys/param.h> +#include <sys/mount.h> +#define HAVE_O_EXLOCK + +// add MACOSX Time Value +#define TimeValue CFTimeValue +#include <CoreFoundation/CoreFoundation.h> +#undef TimeValue + +#endif /* MACOSX */ + +#ifdef DEBUG_OSL_FILE +# define OSL_FILE_TRACE 0 ? (void)(0) : osl_trace +# define PERROR( a, b ) perror( a ); fprintf( stderr, b ) +#else +# define OSL_FILE_TRACE 1 ? (void)(0) : osl_trace +# define PERROR( a, b ) +#endif + +/******************************************************************* + * + * FileHandle_Impl interface + * + ******************************************************************/ +struct FileHandle_Impl +{ + pthread_mutex_t m_mutex; + rtl_String * m_strFilePath; /* holds native file path */ + int m_fd; + + /** State + */ + enum StateBits + { + STATE_SEEKABLE = 1, /* default */ + STATE_READABLE = 2, /* default */ + STATE_WRITEABLE = 4, /* open() sets, write() requires, else osl_File_E_BADF */ + STATE_MODIFIED = 8 /* write() sets, flush() resets */ + }; + int m_state; + + sal_uInt64 m_size; /* file size */ + off_t m_offset; /* physical offset from begin of file */ + off_t m_fileptr; /* logical offset from begin of file */ + + off_t m_bufptr; /* buffer offset from begin of file */ + size_t m_buflen; /* buffer filled [0, m_bufsiz - 1] */ + + size_t m_bufsiz; + sal_uInt8 * m_buffer; + + explicit FileHandle_Impl (int fd, char const * path = "<anon>"); + ~FileHandle_Impl(); + + static void* operator new (size_t n); + static void operator delete (void * p, size_t); + + static size_t getpagesize(); + + sal_uInt64 getPos() const; + oslFileError setPos (sal_uInt64 uPos); + + sal_uInt64 getSize() const; + oslFileError setSize (sal_uInt64 uSize); + + oslFileError readAt ( + off_t nOffset, + void * pBuffer, + size_t nBytesRequested, + sal_uInt64 * pBytesRead); + + oslFileError writeAt ( + off_t nOffset, + void const * pBuffer, + size_t nBytesToWrite, + sal_uInt64 * pBytesWritten); + + oslFileError readFileAt ( + off_t nOffset, + void * pBuffer, + size_t nBytesRequested, + sal_uInt64 * pBytesRead); + + oslFileError writeFileAt ( + off_t nOffset, + void const * pBuffer, + size_t nBytesToWrite, + sal_uInt64 * pBytesWritten); + + oslFileError readLineAt ( + off_t nOffset, + sal_Sequence ** ppSequence, + sal_uInt64 * pBytesRead); + + oslFileError writeSequence_Impl ( + sal_Sequence ** ppSequence, + size_t * pnOffset, + const void * pBuffer, + size_t nBytes); + + oslFileError syncFile(); + + /** Buffer cache / allocator. + */ + class Allocator + { + rtl_cache_type * m_cache; + size_t m_bufsiz; + + Allocator (Allocator const &); + Allocator & operator= (Allocator const &); + + public: + static Allocator & get(); + + void allocate (sal_uInt8 ** ppBuffer, size_t * pnSize); + void deallocate (sal_uInt8 * pBuffer); + + protected: + Allocator(); + ~Allocator(); + }; + + /** Guard. + */ + class Guard + { + pthread_mutex_t * m_mutex; + + public: + explicit Guard(pthread_mutex_t * pMutex); + ~Guard(); + }; +}; + +/******************************************************************* + * + * FileHandle_Impl implementation + * + ******************************************************************/ + +FileHandle_Impl::Allocator & +FileHandle_Impl::Allocator::get() +{ + static Allocator g_aBufferAllocator; + return g_aBufferAllocator; +} + +FileHandle_Impl::Allocator::Allocator() + : m_cache (0), + m_bufsiz (0) +{ + size_t const pagesize = FileHandle_Impl::getpagesize(); + if (size_t(-1) != pagesize) + { + m_cache = rtl_cache_create ( + "osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0); + if (0 != m_cache) + m_bufsiz = pagesize; + } +} +FileHandle_Impl::Allocator::~Allocator() +{ + rtl_cache_destroy (m_cache), m_cache = 0; +} + +void FileHandle_Impl::Allocator::allocate (sal_uInt8 ** ppBuffer, size_t * pnSize) +{ + OSL_PRECOND((0 != ppBuffer) && (0 != pnSize), "FileHandle_Impl::Allocator::allocate(): contract violation"); + *ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz; +} +void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer) +{ + if (0 != pBuffer) + rtl_cache_free (m_cache, pBuffer); +} + +FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex) + : m_mutex (pMutex) +{ + OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer."); + (void) pthread_mutex_lock (m_mutex); // ignoring EINVAL ... +} +FileHandle_Impl::Guard::~Guard() +{ + OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer."); + (void) pthread_mutex_unlock (m_mutex); +} + +FileHandle_Impl::FileHandle_Impl (int fd, char const * path) + : m_strFilePath (0), + m_fd (fd), + m_state (STATE_SEEKABLE | STATE_READABLE), + m_size (0), + m_offset (0), + m_fileptr (0), + m_bufptr (-1), + m_buflen (0), + m_bufsiz (0), + m_buffer (0) +{ + (void) pthread_mutex_init(&m_mutex, 0); + rtl_string_newFromStr (&m_strFilePath, path); + Allocator::get().allocate (&m_buffer, &m_bufsiz); + if (0 != m_buffer) + memset (m_buffer, 0, m_bufsiz); +} +FileHandle_Impl::~FileHandle_Impl() +{ + Allocator::get().deallocate (m_buffer), m_buffer = 0; + rtl_string_release (m_strFilePath), m_strFilePath = 0; + (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ... +} + +void* FileHandle_Impl::operator new (size_t n) +{ + return rtl_allocateMemory(n); +} +void FileHandle_Impl::operator delete (void * p, size_t) +{ + rtl_freeMemory(p); +} + +size_t FileHandle_Impl::getpagesize() +{ +#if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) + return sal::static_int_cast< size_t >(::getpagesize()); +#else /* POSIX */ + return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE)); +#endif /* xBSD || POSIX */ +} + +sal_uInt64 FileHandle_Impl::getPos() const +{ + return sal::static_int_cast< sal_uInt64 >(m_fileptr); +} + +oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos) +{ + OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd, getPos(), uPos); + m_fileptr = sal::static_int_cast< off_t >(uPos); + return osl_File_E_None; +} + +sal_uInt64 FileHandle_Impl::getSize() const +{ + off_t const bufend = std::max((off_t)(0), m_bufptr) + m_buflen; + return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend)); +} + +oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize) +{ + off_t const nSize = sal::static_int_cast< off_t >(uSize); + if (-1 == ftruncate (m_fd, nSize)) + { + /* Failure. Save original result. Try fallback algorithm */ + oslFileError result = oslTranslateFileError (OSL_FET_ERROR, errno); + + /* Check against current size. Fail upon 'shrink' */ + if (uSize <= getSize()) + { + /* Failure upon 'shrink'. Return original result */ + return (result); + } + + /* Save current position */ + off_t const nCurPos = (off_t)lseek (m_fd, (off_t)0, SEEK_CUR); + if (nCurPos == (off_t)(-1)) + return (result); + + /* Try 'expand' via 'lseek()' and 'write()' */ + if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET)) + return (result); + + if (-1 == write (m_fd, (char*)"", (size_t)1)) + { + /* Failure. Restore saved position */ + (void) lseek (m_fd, (off_t)(nCurPos), SEEK_SET); + return (result); + } + + /* Success. Restore saved position */ + if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET)) + return (result); + } + + OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", m_fd, getSize(), nSize); + m_size = sal::static_int_cast< sal_uInt64 >(nSize); + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::readAt ( + off_t nOffset, + void * pBuffer, + size_t nBytesRequested, + sal_uInt64 * pBytesRead) +{ + OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::readAt(): not seekable"); + if (!(m_state & STATE_SEEKABLE)) + return osl_File_E_SPIPE; + + OSL_PRECOND((m_state & STATE_READABLE), "FileHandle_Impl::readAt(): not readable"); + if (!(m_state & STATE_READABLE)) + return osl_File_E_BADF; + +#if defined(LINUX) || defined(SOLARIS) + + ssize_t nBytes = ::pread (m_fd, pBuffer, nBytesRequested, nOffset); + if ((-1 == nBytes) && (EOVERFLOW == errno)) + { + /* Some 'pread()'s fail with EOVERFLOW when reading at (or past) + * end-of-file, different from 'lseek() + read()' behaviour. + * Returning '0 bytes read' and 'osl_File_E_None' instead. + */ + nBytes = 0; + } + if (-1 == nBytes) + return oslTranslateFileError (OSL_FET_ERROR, errno); + +#else /* !(LINUX || SOLARIS) */ + + if (nOffset != m_offset) + { + if (-1 == ::lseek (m_fd, nOffset, SEEK_SET)) + return oslTranslateFileError (OSL_FET_ERROR, errno); + m_offset = nOffset; + } + + ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested); + if (-1 == nBytes) + return oslTranslateFileError (OSL_FET_ERROR, errno); + m_offset += nBytes; + +#endif /* !(LINUX || SOLARIS) */ + + OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd, nOffset, nBytes); + *pBytesRead = nBytes; + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::writeAt ( + off_t nOffset, + void const * pBuffer, + size_t nBytesToWrite, + sal_uInt64 * pBytesWritten) +{ + OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::writeAt(): not seekable"); + if (!(m_state & STATE_SEEKABLE)) + return osl_File_E_SPIPE; + + OSL_PRECOND((m_state & STATE_WRITEABLE), "FileHandle_Impl::writeAt(): not writeable"); + if (!(m_state & STATE_WRITEABLE)) + return osl_File_E_BADF; + +#if defined(LINUX) || defined(SOLARIS) + + ssize_t nBytes = ::pwrite (m_fd, pBuffer, nBytesToWrite, nOffset); + if (-1 == nBytes) + return oslTranslateFileError (OSL_FET_ERROR, errno); + +#else /* !(LINUX || SOLARIS) */ + + if (nOffset != m_offset) + { + if (-1 == ::lseek (m_fd, nOffset, SEEK_SET)) + return oslTranslateFileError (OSL_FET_ERROR, errno); + m_offset = nOffset; + } + + ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite); + if (-1 == nBytes) + return oslTranslateFileError (OSL_FET_ERROR, errno); + m_offset += nBytes; + +#endif /* !(LINUX || SOLARIS) */ + + OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd, nOffset, nBytes); + m_size = std::max (m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes)); + + *pBytesWritten = nBytes; + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::readFileAt ( + off_t nOffset, + void * pBuffer, + size_t nBytesRequested, + sal_uInt64 * pBytesRead) +{ + if (0 == (m_state & STATE_SEEKABLE)) + { + // not seekable (pipe) + ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested); + if (-1 == nBytes) + return oslTranslateFileError (OSL_FET_ERROR, errno); + *pBytesRead = nBytes; + return osl_File_E_None; + } + else if (0 == m_buffer) + { + // not buffered + return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead); + } + else + { + sal_uInt8 * buffer = static_cast<sal_uInt8*>(pBuffer); + for (*pBytesRead = 0; nBytesRequested > 0; ) + { + off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz; + size_t const bufpos = (nOffset % m_bufsiz); + + if (bufptr != m_bufptr) + { + // flush current buffer + oslFileError result = syncFile(); + if (result != osl_File_E_None) + return (result); + m_bufptr = -1, m_buflen = 0; + + if (nBytesRequested >= m_bufsiz) + { + // buffer too small, read through from file + sal_uInt64 uDone = 0; + result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone); + if (result != osl_File_E_None) + return (result); + + nBytesRequested -= uDone, *pBytesRead += uDone; + return osl_File_E_None; + } + + // update buffer (pointer) + sal_uInt64 uDone = 0; + result = readAt (bufptr, m_buffer, m_bufsiz, &uDone); + if (result != osl_File_E_None) + return (result); + m_bufptr = bufptr, m_buflen = uDone; + } + if (bufpos >= m_buflen) + { + // end of file + return osl_File_E_None; + } + + size_t const bytes = std::min (m_buflen - bufpos, nBytesRequested); + OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes); + + memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes); + nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes; + } + return osl_File_E_None; + } +} + +oslFileError FileHandle_Impl::writeFileAt ( + off_t nOffset, + void const * pBuffer, + size_t nBytesToWrite, + sal_uInt64 * pBytesWritten) +{ + if (0 == (m_state & STATE_SEEKABLE)) + { + // not seekable (pipe) + ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite); + if (-1 == nBytes) + return oslTranslateFileError (OSL_FET_ERROR, errno); + *pBytesWritten = nBytes; + return osl_File_E_None; + } + else if (0 == m_buffer) + { + // not buffered + return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten); + } + else + { + sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer); + for (*pBytesWritten = 0; nBytesToWrite > 0; ) + { + off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz; + size_t const bufpos = (nOffset % m_bufsiz); + if (bufptr != m_bufptr) + { + // flush current buffer + oslFileError result = syncFile(); + if (result != osl_File_E_None) + return (result); + m_bufptr = -1, m_buflen = 0; + + if (nBytesToWrite >= m_bufsiz) + { + // buffer to small, write through to file + sal_uInt64 uDone = 0; + result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone); + if (result != osl_File_E_None) + return (result); + if (uDone != nBytesToWrite) + return osl_File_E_IO; + + nBytesToWrite -= uDone, *pBytesWritten += uDone; + return osl_File_E_None; + } + + // update buffer (pointer) + sal_uInt64 uDone = 0; + result = readAt (bufptr, m_buffer, m_bufsiz, &uDone); + if (result != osl_File_E_None) + return (result); + m_bufptr = bufptr, m_buflen = uDone; + } + + size_t const bytes = std::min (m_bufsiz - bufpos, nBytesToWrite); + OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes); + + memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes); + nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes; + + m_buflen = std::max(m_buflen, bufpos + bytes); + m_state |= STATE_MODIFIED; + } + return osl_File_E_None; + } +} + +oslFileError FileHandle_Impl::readLineAt ( + off_t nOffset, + sal_Sequence ** ppSequence, + sal_uInt64 * pBytesRead) +{ + oslFileError result = osl_File_E_None; + + off_t bufptr = nOffset / m_bufsiz * m_bufsiz; + if (bufptr != m_bufptr) + { + /* flush current buffer */ + result = syncFile(); + if (result != osl_File_E_None) + return (result); + + /* update buffer (pointer) */ + sal_uInt64 uDone = 0; + result = readAt (bufptr, m_buffer, m_bufsiz, &uDone); + if (result != osl_File_E_None) + return (result); + + m_bufptr = bufptr, m_buflen = uDone; + } + + static int const LINE_STATE_BEGIN = 0; + static int const LINE_STATE_CR = 1; + static int const LINE_STATE_LF = 2; + + size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0; + int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN; + + for ( ; state != LINE_STATE_LF; ) + { + if (curpos >= m_buflen) + { + /* buffer examined */ + if (0 < (curpos - bufpos)) + { + /* flush buffer to sequence */ + result = writeSequence_Impl ( + ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos); + if (result != osl_File_E_None) + return (result); + *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos; + } + + bufptr = nOffset / m_bufsiz * m_bufsiz; + if (bufptr != m_bufptr) + { + /* update buffer (pointer) */ + sal_uInt64 uDone = 0; + result = readAt (bufptr, m_buffer, m_bufsiz, &uDone); + if (result != osl_File_E_None) + return (result); + m_bufptr = bufptr, m_buflen = uDone; + } + + bufpos = nOffset - m_bufptr, curpos = bufpos; + if (bufpos >= m_buflen) + break; + } + switch (state) + { + case LINE_STATE_CR: + state = LINE_STATE_LF; + switch (m_buffer[curpos]) + { + case 0x0A: /* CRLF */ + /* eat current char */ + curpos++; + break; + default: /* single CR */ + /* keep current char */ + break; + } + break; + default: + /* determine next state */ + switch (m_buffer[curpos]) + { + case 0x0A: /* single LF */ + state = LINE_STATE_LF; + break; + case 0x0D: /* CR */ + state = LINE_STATE_CR; + break; + default: /* advance to next char */ + curpos++; + break; + } + if (state != LINE_STATE_BEGIN) + { + /* store (and eat) the newline char */ + m_buffer[curpos] = 0x0A, curpos++; + + /* flush buffer to sequence */ + result = writeSequence_Impl ( + ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1); + if (result != osl_File_E_None) + return (result); + *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos; + } + break; + } + } + + result = writeSequence_Impl (ppSequence, &dstpos, 0, 0); + if (result != osl_File_E_None) + return (result); + if (0 < dstpos) + return osl_File_E_None; + if (bufpos >= m_buflen) + return osl_File_E_AGAIN; + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::writeSequence_Impl ( + sal_Sequence ** ppSequence, + size_t * pnOffset, + const void * pBuffer, + size_t nBytes) +{ + sal_Int32 nElements = *pnOffset + nBytes; + if (!*ppSequence) + { + /* construct sequence */ + rtl_byte_sequence_constructNoDefault(ppSequence, nElements); + } + else if (nElements != (*ppSequence)->nElements) + { + /* resize sequence */ + rtl_byte_sequence_realloc(ppSequence, nElements); + } + if (*ppSequence != 0) + { + /* fill sequence */ + memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes; + } + return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM; +} + +oslFileError FileHandle_Impl::syncFile() +{ + oslFileError result = osl_File_E_None; + if (m_state & STATE_MODIFIED) + { + sal_uInt64 uDone = 0; + result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone); + if (result != osl_File_E_None) + return (result); + if (uDone != m_buflen) + return osl_File_E_IO; + m_state &= ~STATE_MODIFIED; + } + return (result); +} + +/**************************************************************************** + * osl_createFileHandleFromFD + ***************************************************************************/ +extern "C" oslFileHandle osl_createFileHandleFromFD( int fd ) +{ + if (-1 == fd) + return 0; // EINVAL + + struct stat aFileStat; + if (-1 == fstat (fd, &aFileStat)) + return 0; // EBADF + + FileHandle_Impl * pImpl = new FileHandle_Impl (fd); + if (0 == pImpl) + return 0; // ENOMEM + + // assume writeable + pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE; + if (!S_ISREG(aFileStat.st_mode)) + { + /* not a regular file, mark not seekable */ + pImpl->m_state &= ~FileHandle_Impl::STATE_SEEKABLE; + } + else + { + /* regular file, init current size */ + pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size); + } + + OSL_FILE_TRACE("osl_createFileHandleFromFD(%d, writeable) => %s", + pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath)); + return (oslFileHandle)(pImpl); +} + +/******************************************************************* + * osl_file_adjustLockFlags + ******************************************************************/ +static int osl_file_adjustLockFlags (const char * path, int flags) +{ +#ifdef MACOSX + /* + * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way + * that makes it impossible for OOo to create a backup copy of the + * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by + * the OOo file handling, so we need to check the path of the file + * for the filesystem name. + */ + struct statfs s; + if( 0 <= statfs( path, &s ) ) + { + if( 0 == strncmp("afpfs", s.f_fstypename, 5) ) + { + flags &= ~O_EXLOCK; + flags |= O_SHLOCK; + } + else + { + /* Needed flags to allow opening a webdav file */ + flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK); + } + } +#endif /* MACOSX */ + + (void) path; + return flags; +} + +/**************************************************************************** + * osl_file_queryLocking + ***************************************************************************/ +struct Locking_Impl +{ + int m_enabled; + Locking_Impl() : m_enabled(0) + { +#ifndef HAVE_O_EXLOCK + m_enabled = ((getenv("SAL_ENABLE_FILE_LOCKING") != 0) || (getenv("STAR_ENABLE_FILE_LOCKING") != 0)); +#endif /* HAVE_O_EXLOCK */ + } +}; +static int osl_file_queryLocking (sal_uInt32 uFlags) +{ + if (!(uFlags & osl_File_OpenFlag_NoLock)) + { + if ((uFlags & osl_File_OpenFlag_Write) || (uFlags & osl_File_OpenFlag_Create)) + { + static Locking_Impl g_locking; + return (g_locking.m_enabled != 0); + } + } + return 0; +} + +/**************************************************************************** + * osl_openFile + ***************************************************************************/ +#ifdef HAVE_O_EXLOCK +#define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK ) +#define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR | O_EXLOCK | O_NONBLOCK ) +#else +#define OPEN_WRITE_FLAGS ( O_RDWR ) +#define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR ) +#endif + +oslFileError +SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags ) +{ + oslFileError eRet; + + if ((ustrFileURL == 0) || (ustrFileURL->length == 0) || (pHandle == 0)) + return osl_File_E_INVAL; + + /* convert file URL to system path */ + char buffer[PATH_MAX]; + eRet = FileURLToPath (buffer, sizeof(buffer), ustrFileURL); + if (eRet != osl_File_E_None) + return eRet; +#ifdef MACOSX + if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0) + return oslTranslateFileError (OSL_FET_ERROR, errno); +#endif /* MACOSX */ + + /* set mode and flags */ + int mode = S_IRUSR | S_IRGRP | S_IROTH; + int flags = O_RDONLY; + if (uFlags & osl_File_OpenFlag_Write) + { + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + flags = OPEN_WRITE_FLAGS; + } + if (uFlags & osl_File_OpenFlag_Create) + { + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + flags = OPEN_CREATE_FLAGS; + } + if (uFlags & osl_File_OpenFlag_NoLock) + { +#ifdef HAVE_O_EXLOCK + flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK); +#endif /* HAVE_O_EXLOCK */ + } + else + { + flags = osl_file_adjustLockFlags (buffer, flags); + } + + /* open the file */ + int fd = open( buffer, flags, mode ); + if (-1 == fd) + return oslTranslateFileError (OSL_FET_ERROR, errno); + + /* reset O_NONBLOCK flag */ + if (flags & O_NONBLOCK) + { + int f = fcntl (fd, F_GETFL, 0); + if (-1 == f) + { + eRet = oslTranslateFileError (OSL_FET_ERROR, errno); + (void) close(fd); + return eRet; + } + if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK))) + { + eRet = oslTranslateFileError (OSL_FET_ERROR, errno); + (void) close(fd); + return eRet; + } + } + + /* get file status (mode, size) */ + struct stat aFileStat; + if (-1 == fstat (fd, &aFileStat)) + { + eRet = oslTranslateFileError (OSL_FET_ERROR, errno); + (void) close(fd); + return eRet; + } + if (!S_ISREG(aFileStat.st_mode)) + { + /* we only open regular files here */ + (void) close(fd); + return osl_File_E_INVAL; + } + + if (osl_file_queryLocking (uFlags)) + { +#ifdef MACOSX + if (-1 == flock (fd, LOCK_EX | LOCK_NB)) + { + /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */ + if ((errno != ENOTSUP) || ((-1 == flock (fd, LOCK_SH | LOCK_NB)) && (errno != ENOTSUP))) + { + eRet = oslTranslateFileError (OSL_FET_ERROR, errno); + (void) close(fd); + return eRet; + } + } +#else /* F_SETLK */ + { + struct flock aflock; + + aflock.l_type = F_WRLCK; + aflock.l_whence = SEEK_SET; + aflock.l_start = 0; + aflock.l_len = 0; + + if (-1 == fcntl (fd, F_SETLK, &aflock)) + { + eRet = oslTranslateFileError (OSL_FET_ERROR, errno); + (void) close(fd); + return eRet; + } + } +#endif /* F_SETLK */ + } + + /* allocate memory for impl structure */ + FileHandle_Impl * pImpl = new FileHandle_Impl (fd, buffer); + if (!pImpl) + { + eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM); + (void) close(fd); + return eRet; + } + if (flags & O_RDWR) + pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE; + pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size); + + OSL_TRACE("osl_openFile(%d, %s) => %s", pImpl->m_fd, + flags & O_RDWR ? "writeable":"readonly", + rtl_string_getStr(pImpl->m_strFilePath)); + + *pHandle = (oslFileHandle)(pImpl); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_closeFile */ +/****************************************************************************/ +oslFileError +SAL_CALL osl_closeFile( oslFileHandle Handle ) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((pImpl == 0) || (pImpl->m_fd < 0)) + return osl_File_E_INVAL; + + (void) pthread_mutex_lock (&(pImpl->m_mutex)); + + /* close(2) implicitly (and unconditionally) unlocks */ + OSL_TRACE("osl_closeFile(%d) => %s", pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath)); + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + { + /* close, ignoring double failure */ + (void) close (pImpl->m_fd); + } + else if (-1 == close (pImpl->m_fd)) + { + /* translate error code */ + result = oslTranslateFileError (OSL_FET_ERROR, errno); + } + + (void) pthread_mutex_unlock (&(pImpl->m_mutex)); + delete pImpl; + return (result); +} + +/************************************************ + * osl_syncFile + ***********************************************/ +oslFileError +SAL_CALL osl_syncFile(oslFileHandle Handle) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + + OSL_TRACE("osl_syncFile(%d)", pImpl->m_fd); + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + return (result); + if (-1 == fsync (pImpl->m_fd)) + return oslTranslateFileError (OSL_FET_ERROR, errno); + + return osl_File_E_None; +} + +/******************************************* + osl_mapFile +********************************************/ +oslFileError +SAL_CALL osl_mapFile ( + oslFileHandle Handle, + void** ppAddr, + sal_uInt64 uLength, + sal_uInt64 uOffset, + sal_uInt32 uFlags +) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == ppAddr)) + return osl_File_E_INVAL; + *ppAddr = 0; + + static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max(); + if (g_limit_size_t < uLength) + return osl_File_E_OVERFLOW; + size_t const nLength = sal::static_int_cast< size_t >(uLength); + + static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max(); + if (g_limit_off_t < uOffset) + return osl_File_E_OVERFLOW; + off_t const nOffset = sal::static_int_cast< off_t >(uOffset); + + void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset); + if (MAP_FAILED == p) + return oslTranslateFileError(OSL_FET_ERROR, errno); + *ppAddr = p; + + if (uFlags & osl_File_MapFlag_RandomAccess) + { + // Determine memory pagesize. + size_t const nPageSize = FileHandle_Impl::getpagesize(); + if (size_t(-1) != nPageSize) + { + /* + * Pagein, touching first byte of every memory page. + * Note: volatile disables optimizing the loop away. + */ + sal_uInt8 * pData (reinterpret_cast<sal_uInt8*>(*ppAddr)); + size_t nSize (nLength); + + volatile sal_uInt8 c = 0; + while (nSize > nPageSize) + { + c ^= pData[0]; + pData += nPageSize; + nSize -= nPageSize; + } + if (nSize > 0) + { + c^= pData[0]; + pData += nSize; + nSize -= nSize; + } + } + } + if (uFlags & osl_File_MapFlag_WillNeed) + { + // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable + // effect of not returning until the data has actually been paged in, so + // that its net effect would typically be to slow down the process + // (which could start processing at the beginning of the data while the + // OS simultaneously pages in the rest); on other platforms, it remains + // to be evaluated whether madvise or equivalent is available and + // actually useful: +#if defined MACOSX + int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED); + if (e != 0) + { + OSL_TRACE( + "posix_madvise(..., POSIX_MADV_WILLNEED) failed with %d", e); + } +#elif defined SOLARIS + if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0) + { + OSL_TRACE("madvise(..., MADV_WILLNEED) failed with %d", errno); + } +#endif + } + return osl_File_E_None; +} + +/******************************************* + osl_unmapFile +********************************************/ +oslFileError +SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength) +{ + if (0 == pAddr) + return osl_File_E_INVAL; + + static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max(); + if (g_limit_size_t < uLength) + return osl_File_E_OVERFLOW; + size_t const nLength = sal::static_int_cast< size_t >(uLength); + + if (-1 == munmap(static_cast<char*>(pAddr), nLength)) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + return osl_File_E_None; +} + +/******************************************* + osl_readLine +********************************************/ +oslFileError +SAL_CALL osl_readLine ( + oslFileHandle Handle, + sal_Sequence ** ppSequence) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == ppSequence)) + return osl_File_E_INVAL; + sal_uInt64 uBytesRead = 0; + + // read at current fileptr; fileptr += uBytesRead; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->readLineAt ( + pImpl->m_fileptr, ppSequence, &uBytesRead); + if (result == osl_File_E_None) + pImpl->m_fileptr += uBytesRead; + return (result); +} + +/******************************************* + osl_readFile +********************************************/ +oslFileError +SAL_CALL osl_readFile ( + oslFileHandle Handle, + void * pBuffer, + sal_uInt64 uBytesRequested, + sal_uInt64 * pBytesRead) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesRead)) + return osl_File_E_INVAL; + + static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); + if (g_limit_ssize_t < uBytesRequested) + return osl_File_E_OVERFLOW; + size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested); + + // read at current fileptr; fileptr += *pBytesRead; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->readFileAt ( + pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead); + if (result == osl_File_E_None) + pImpl->m_fileptr += *pBytesRead; + return (result); +} + +/******************************************* + osl_writeFile +********************************************/ +oslFileError +SAL_CALL osl_writeFile ( + oslFileHandle Handle, + const void * pBuffer, + sal_uInt64 uBytesToWrite, + sal_uInt64 * pBytesWritten) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten)) + return osl_File_E_INVAL; + if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE)) + return osl_File_E_BADF; + + static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); + if (g_limit_ssize_t < uBytesToWrite) + return osl_File_E_OVERFLOW; + size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite); + + // write at current fileptr; fileptr += *pBytesWritten; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->writeFileAt ( + pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten); + if (result == osl_File_E_None) + pImpl->m_fileptr += *pBytesWritten; + return (result); +} + +/******************************************* + osl_readFileAt +********************************************/ +oslFileError +SAL_CALL osl_readFileAt ( + oslFileHandle Handle, + sal_uInt64 uOffset, + void* pBuffer, + sal_uInt64 uBytesRequested, + sal_uInt64* pBytesRead) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesRead)) + return osl_File_E_INVAL; + if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE)) + return osl_File_E_SPIPE; + + static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max(); + if (g_limit_off_t < uOffset) + return osl_File_E_OVERFLOW; + off_t const nOffset = sal::static_int_cast< off_t >(uOffset); + + static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); + if (g_limit_ssize_t < uBytesRequested) + return osl_File_E_OVERFLOW; + size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested); + + // read at specified fileptr + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + return pImpl->readFileAt (nOffset, pBuffer, nBytesRequested, pBytesRead); +} + +/******************************************* + osl_writeFileAt +********************************************/ +oslFileError +SAL_CALL osl_writeFileAt ( + oslFileHandle Handle, + sal_uInt64 uOffset, + const void* pBuffer, + sal_uInt64 uBytesToWrite, + sal_uInt64* pBytesWritten) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten)) + return osl_File_E_INVAL; + if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE)) + return osl_File_E_SPIPE; + if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE)) + return osl_File_E_BADF; + + static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max(); + if (g_limit_off_t < uOffset) + return osl_File_E_OVERFLOW; + off_t const nOffset = sal::static_int_cast< off_t >(uOffset); + + static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); + if (g_limit_ssize_t < uBytesToWrite) + return osl_File_E_OVERFLOW; + size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite); + + // write at specified fileptr + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + return pImpl->writeFileAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten); +} + +/****************************************************************************/ +/* osl_isEndOfFile */ +/****************************************************************************/ +oslFileError +SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF ) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pIsEOF)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pIsEOF = (pImpl->getPos() == pImpl->getSize()); + return osl_File_E_None; +} + +/************************************************ + * osl_getFilePos + ***********************************************/ +oslFileError +SAL_CALL osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos ) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pPos)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pPos = pImpl->getPos(); + return osl_File_E_None; +} + +/******************************************* + osl_setFilePos +********************************************/ +oslFileError +SAL_CALL osl_setFilePos (oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd)) + return osl_File_E_INVAL; + + static sal_Int64 const g_limit_off_t = std::numeric_limits< off_t >::max(); + if (g_limit_off_t < uOffset) + return osl_File_E_OVERFLOW; + off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset); + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + switch(uHow) + { + case osl_Pos_Absolut: + if (0 > nOffset) + return osl_File_E_INVAL; + break; + + case osl_Pos_Current: + nPos = sal::static_int_cast< off_t >(pImpl->getPos()); + if ((0 > nOffset) && (-1*nOffset > nPos)) + return osl_File_E_INVAL; + if (g_limit_off_t < nPos + nOffset) + return osl_File_E_OVERFLOW; + break; + + case osl_Pos_End: + nPos = sal::static_int_cast< off_t >(pImpl->getSize()); + if ((0 > nOffset) && (-1*nOffset > nPos)) + return osl_File_E_INVAL; + if (g_limit_off_t < nPos + nOffset) + return osl_File_E_OVERFLOW; + break; + + default: + return osl_File_E_INVAL; + } + + return pImpl->setPos (nPos + nOffset); +} + +/**************************************************************************** + * osl_getFileSize + ****************************************************************************/ +oslFileError +SAL_CALL osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize ) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pSize)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pSize = pImpl->getSize(); + return osl_File_E_None; +} + +/************************************************ + * osl_setFileSize + ***********************************************/ +oslFileError +SAL_CALL osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize ) +{ + FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || (-1 == pImpl->m_fd)) + return osl_File_E_INVAL; + if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE)) + return osl_File_E_BADF; + + static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max(); + if (g_limit_off_t < uSize) + return osl_File_E_OVERFLOW; + + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + return (result); + pImpl->m_bufptr = -1, pImpl->m_buflen = 0; + + return pImpl->setSize (uSize); +} diff --git a/sal/osl/unx/file_error_transl.cxx b/sal/osl/unx/file_error_transl.cxx new file mode 100644 index 000000000000..3de829afc391 --- /dev/null +++ b/sal/osl/unx/file_error_transl.cxx @@ -0,0 +1,255 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + + #ifndef _ERRNO_H + #include <errno.h> + #endif + + #ifndef _FILE_ERROR_TRANSL_H_ + #include "file_error_transl.h" + #endif + + #ifndef _OSL_DIAGNOSE_H_ + #include <osl/diagnose.h> + #endif + + +/******************************************** + * oslTranslateFileError + *******************************************/ + +oslFileError oslTranslateFileError(sal_Bool bIsError, int Errno) +{ + oslFileError osl_error = osl_File_E_invalidError; + + OSL_ENSURE((bIsError && (0 != Errno)) || (!bIsError && (0 == Errno)), "oslTranslateFileError strange input combination!"); + + /* Have a look at file_error_transl.h for + the reason that we do this here */ + if (bIsError && (0 == Errno)) + return osl_error; + + switch(Errno) + { + case 0: + osl_error = osl_File_E_None; + break; + + case EPERM: + osl_error = osl_File_E_PERM; + break; + + case ENOENT: + osl_error = osl_File_E_NOENT; + break; + + case ESRCH: + osl_error = osl_File_E_SRCH; + break; + + case EINTR: + osl_error = osl_File_E_INTR; + break; + + case EIO: + osl_error = osl_File_E_IO; + break; + + case ENXIO: + osl_error = osl_File_E_IO; + break; + + case E2BIG: + osl_error = osl_File_E_2BIG; + break; + + case ENOEXEC: + osl_error = osl_File_E_NOEXEC; + break; + + case EBADF: + osl_error = osl_File_E_BADF; + break; + + case ECHILD: + osl_error = osl_File_E_CHILD; + break; + + case EAGAIN: + osl_error = osl_File_E_AGAIN; + break; + + case ENOMEM: + osl_error = osl_File_E_NOMEM; + break; + + case EACCES: + osl_error = osl_File_E_ACCES; + break; + + case EFAULT: + osl_error = osl_File_E_FAULT; + break; + + case EBUSY: + osl_error = osl_File_E_BUSY; + break; + + case EEXIST: + osl_error = osl_File_E_EXIST; + break; + + case EXDEV: + osl_error = osl_File_E_XDEV; + break; + + case ENODEV: + osl_error = osl_File_E_NODEV; + break; + + case ENOTDIR: + osl_error = osl_File_E_NOTDIR; + break; + + case EISDIR: + osl_error = osl_File_E_ISDIR; + break; + + case EINVAL: + osl_error = osl_File_E_INVAL; + break; + + case ENFILE: + osl_error = osl_File_E_NFILE; + break; + + case EMFILE: + osl_error = osl_File_E_MFILE; + break; + + case ENOTTY: + osl_error = osl_File_E_NOTTY; + break; + + case EFBIG: + osl_error = osl_File_E_FBIG; + break; + + case ENOSPC: + osl_error = osl_File_E_NOSPC; + break; + + case ESPIPE: + osl_error = osl_File_E_SPIPE; + break; + + case EROFS: + osl_error = osl_File_E_ROFS; + break; + + case EMLINK: + osl_error = osl_File_E_MLINK; + break; + + case EPIPE: + osl_error = osl_File_E_PIPE; + break; + + case EDOM: + osl_error = osl_File_E_DOM; + break; + + case ERANGE: + osl_error = osl_File_E_RANGE; + break; + + case EDEADLK: + osl_error = osl_File_E_DEADLK; + break; + + case ENAMETOOLONG: + osl_error = osl_File_E_NAMETOOLONG; + break; + + case ENOLCK: + osl_error = osl_File_E_NOLCK; + break; + + case ENOSYS: + osl_error = osl_File_E_NOSYS; + break; + + case ENOTEMPTY: + osl_error = osl_File_E_NOTEMPTY; + break; + + case ELOOP: + osl_error = osl_File_E_LOOP; + break; + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) + case EILSEQ: + osl_error = osl_File_E_ILSEQ; + break; +#endif /* MACOSX */ + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) + case ENOLINK: + osl_error = osl_File_E_NOLINK; + break; +#endif /* MACOSX */ + +#if !(defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) + case EMULTIHOP: + osl_error = osl_File_E_MULTIHOP; + break; +#endif /* MACOSX */ + + case EUSERS: + osl_error = osl_File_E_USERS; + break; + + case EOVERFLOW: + osl_error = osl_File_E_OVERFLOW; + break; + + case ETIMEDOUT: + osl_error = osl_File_E_TIMEDOUT; + break; + + default: + /* FIXME translateFileError: is this alright? Or add a new one: osl_File_E_Unknown? */ + osl_error = osl_File_E_invalidError; + break; + } + + return osl_error; +} + diff --git a/sal/osl/unx/file_error_transl.h b/sal/osl/unx/file_error_transl.h new file mode 100644 index 000000000000..59d7b1d9faec --- /dev/null +++ b/sal/osl/unx/file_error_transl.h @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _FILE_ERROR_TRANSL_H_ +#define _FILE_ERROR_TRANSL_H_ + +#include <osl/file.h> +#include <sal/types.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************* + oslTranslateFileError + Translate errno's to osl file errors + + @param bIsError [in] specifies if nErrno + should be interpreted as error, + some libc functions signaling an error + but errno is nevertheless 0 in this + case the function should at least + return osl_File_E_Unknown but in no + case osl_File_E_None! + + @param nErrno [in] the errno if errno is 0 + and bIsError is true the function + returns osl_File_E_Unknown + + @returns the osl error code appropriate to + the errno + + *********************************************/ + +#define OSL_FET_SUCCESS sal_False +#define OSL_FET_ERROR sal_True + +oslFileError oslTranslateFileError(sal_Bool bIsError, int Errno); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sal/osl/unx/file_impl.hxx b/sal/osl/unx/file_impl.hxx new file mode 100644 index 000000000000..5dee69f29b2e --- /dev/null +++ b/sal/osl/unx/file_impl.hxx @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_FILE_IMPL_HXX +#define INCLUDED_FILE_IMPL_HXX + +#include "osl/file.h" +#include <stddef.h> + +struct DirectoryItem_Impl +{ + sal_Int32 m_RefCount; + + rtl_uString * m_ustrFilePath; /* holds native file name */ + unsigned char m_DType; + + explicit DirectoryItem_Impl( + rtl_uString * ustrFilePath, unsigned char DType = 0); + ~DirectoryItem_Impl(); + + static void * operator new(size_t n); + static void operator delete (void * p, size_t); + + void acquire(); /* @see osl_acquireDirectoryItem() */ + void release(); /* @see osl_releaseDirectoryItem() */ + + oslFileType getFileType() const; +}; + +#endif /* INCLUDED_FILE_IMPL_HXX */ diff --git a/sal/osl/unx/file_misc.cxx b/sal/osl/unx/file_misc.cxx new file mode 100644 index 000000000000..331b91cb1626 --- /dev/null +++ b/sal/osl/unx/file_misc.cxx @@ -0,0 +1,1101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/file.hxx" + +#include "osl/diagnose.h" +#include "osl/thread.h" +#include <osl/signal.h> +#include "rtl/alloc.h" + +#include "system.h" +#include "file_impl.hxx" +#include "file_error_transl.h" +#include "file_path_helper.hxx" +#include "file_url.h" +#include "uunxapi.hxx" + +#include <sys/types.h> +#include <errno.h> +#include <dirent.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include <algorithm> + +/************************************************************************ + * ToDo + * + * - Fix: check for corresponding struct sizes in exported functions + * - check size/use of oslDirectory + * - check size/use of oslDirectoryItem + ***********************************************************************/ +/****************************************************************************** + * + * Data Type Definition + * + ******************************************************************************/ + +typedef struct +{ + rtl_uString* ustrPath; /* holds native directory path */ + DIR* pDirStruct; +} oslDirectoryImpl; + +#if 0 +/* FIXME: reintroducing this may save some extra bytes per Item */ +typedef struct +{ + rtl_uString* ustrFileName; /* holds native file name */ + rtl_uString* ustrDirPath; /* holds native dir path */ + sal_uInt32 RefCount; +} oslDirectoryItemImpl; +#endif + +DirectoryItem_Impl::DirectoryItem_Impl( + rtl_uString * ustrFilePath, unsigned char DType) + : m_RefCount (1), + m_ustrFilePath (ustrFilePath), + m_DType (DType) +{ + if (m_ustrFilePath != 0) + rtl_uString_acquire(m_ustrFilePath); +} +DirectoryItem_Impl::~DirectoryItem_Impl() +{ + if (m_ustrFilePath != 0) + rtl_uString_release(m_ustrFilePath); +} + +void * DirectoryItem_Impl::operator new(size_t n) +{ + return rtl_allocateMemory(n); +} +void DirectoryItem_Impl::operator delete(void * p, size_t) +{ + rtl_freeMemory(p); +} + +void DirectoryItem_Impl::acquire() +{ + ++m_RefCount; +} +void DirectoryItem_Impl::release() +{ + if (0 == --m_RefCount) + delete this; +} + +oslFileType DirectoryItem_Impl::getFileType() const +{ + switch (m_DType) + { +#ifdef _DIRENT_HAVE_D_TYPE + case DT_LNK: + return osl_File_Type_Link; + case DT_DIR: + return osl_File_Type_Directory; + case DT_REG: + return osl_File_Type_Regular; + case DT_FIFO: + return osl_File_Type_Fifo; + case DT_SOCK: + return osl_File_Type_Socket; + case DT_CHR: + case DT_BLK: + return osl_File_Type_Special; +#endif /* _DIRENT_HAVE_D_TYPE */ + default: + break; + } + return osl_File_Type_Unknown; +} + +/****************************************************************************** + * + * C-String Function Declarations + * + *****************************************************************************/ + +static oslFileError osl_psz_createDirectory(const sal_Char* pszPath); +static oslFileError osl_psz_removeDirectory(const sal_Char* pszPath); + +/******************************************************************* + * osl_openDirectory + ******************************************************************/ + +oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirectory* pDirectory) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError eRet; + + char path[PATH_MAX]; + + if ((0 == ustrDirectoryURL) || (0 == ustrDirectoryURL->length) || (0 == pDirectory)) + return osl_File_E_INVAL; + + /* convert file URL to system path */ + eRet = osl_getSystemPathFromFileURL_Ex(ustrDirectoryURL, &ustrSystemPath, sal_False); + + if( osl_File_E_None != eRet ) + return eRet; + + osl_systemPathRemoveSeparator(ustrSystemPath); + + /* convert unicode path to text */ + if ( UnicodeToText( path, PATH_MAX, ustrSystemPath->buffer, ustrSystemPath->length ) +#ifdef MACOSX + && macxp_resolveAlias( path, PATH_MAX ) == 0 +#endif /* MACOSX */ + ) + { + /* open directory */ + DIR *pdir = opendir( path ); + + if( pdir ) + { + /* create and initialize impl structure */ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) ); + + if( pDirImpl ) + { + pDirImpl->pDirStruct = pdir; + pDirImpl->ustrPath = ustrSystemPath; + + *pDirectory = (oslDirectory) pDirImpl; + return osl_File_E_None; + } + else + { + errno = ENOMEM; + closedir( pdir ); + } + } + else + { +#ifdef DEBUG_OSL_FILE + perror ("osl_openDirectory"); fprintf (stderr, path); +#endif + } + } + + rtl_uString_release( ustrSystemPath ); + + return oslTranslateFileError(OSL_FET_ERROR, errno); +} + +/****************************************************************************/ +/* osl_closeDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory ) +{ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) Directory; + oslFileError err = osl_File_E_None; + + OSL_ASSERT( Directory ); + + if( NULL == pDirImpl ) + return osl_File_E_INVAL; + + /* close directory */ + if( closedir( pDirImpl->pDirStruct ) ) + { + err = oslTranslateFileError(OSL_FET_ERROR, errno); + } + + /* cleanup members */ + rtl_uString_release( pDirImpl->ustrPath ); + + rtl_freeMemory( pDirImpl ); + + return err; +} + +/********************************************** + * osl_readdir_impl_ + * + * readdir wrapper, filters out "." and ".." + * on request + *********************************************/ + +static struct dirent* osl_readdir_impl_(DIR* pdir, sal_Bool bFilterLocalAndParentDir) +{ + struct dirent* pdirent; + + while ((pdirent = readdir(pdir)) != NULL) + { + if (bFilterLocalAndParentDir && + ((0 == strcmp(pdirent->d_name, ".")) || (0 == strcmp(pdirent->d_name, "..")))) + continue; + else + break; + } + + return pdirent; +} + +/**************************************************************************** + * osl_getNextDirectoryItem + ***************************************************************************/ + +oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirectoryItem* pItem, sal_uInt32 /*uHint*/) +{ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*)Directory; + rtl_uString* ustrFileName = NULL; + rtl_uString* ustrFilePath = NULL; + struct dirent* pEntry; + + OSL_ASSERT(Directory); + OSL_ASSERT(pItem); + + if ((NULL == Directory) || (NULL == pItem)) + return osl_File_E_INVAL; + + pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, sal_True); + + if (NULL == pEntry) + return osl_File_E_NOENT; + + +#if defined(MACOSX) + + // convert decomposed filename to precomposed unicode + char composed_name[BUFSIZ]; + CFMutableStringRef strRef = CFStringCreateMutable (NULL, 0 ); + CFStringAppendCString( strRef, pEntry->d_name, kCFStringEncodingUTF8 ); //UTF8 is default on Mac OSX + CFStringNormalize( strRef, kCFStringNormalizationFormC ); + CFStringGetCString( strRef, composed_name, BUFSIZ, kCFStringEncodingUTF8 ); + CFRelease( strRef ); + rtl_string2UString( &ustrFileName, composed_name, strlen( composed_name), + osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + +#else // not MACOSX + /* convert file name to unicode */ + rtl_string2UString( &ustrFileName, pEntry->d_name, strlen( pEntry->d_name ), + osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(ustrFileName != 0); + +#endif + + osl_systemPathMakeAbsolutePath(pDirImpl->ustrPath, ustrFileName, &ustrFilePath); + rtl_uString_release( ustrFileName ); + + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(*pItem); + if (0 != pImpl) + { + pImpl->release(), pImpl = 0; + } +#ifdef _DIRENT_HAVE_D_TYPE + pImpl = new DirectoryItem_Impl(ustrFilePath, pEntry->d_type); +#else + pImpl = new DirectoryItem_Impl(ustrFilePath); +#endif /* _DIRENT_HAVE_D_TYPE */ + *pItem = pImpl; + rtl_uString_release( ustrFilePath ); + + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_getDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getDirectoryItem( rtl_uString* ustrFileURL, oslDirectoryItem* pItem ) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError osl_error = osl_File_E_INVAL; + + OSL_ASSERT(ustrFileURL); + OSL_ASSERT(pItem); + + if (0 == ustrFileURL->length || NULL == pItem) + return osl_File_E_INVAL; + + osl_error = osl_getSystemPathFromFileURL_Ex(ustrFileURL, &ustrSystemPath, sal_False); + if (osl_File_E_None != osl_error) + return osl_error; + + osl_systemPathRemoveSeparator(ustrSystemPath); + + if (-1 == access_u(ustrSystemPath, F_OK)) + { + osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); + } + else + { + *pItem = new DirectoryItem_Impl(ustrSystemPath); + } + rtl_uString_release(ustrSystemPath); + + return osl_error; +} + + +/****************************************************************************/ +/* osl_acquireDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item ) +{ + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item); + if (0 == pImpl) + return osl_File_E_INVAL; + + pImpl->acquire(); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_releaseDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item ) +{ + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item); + if (0 == pImpl) + return osl_File_E_INVAL; + + pImpl->release(); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_createDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_createDirectory( rtl_uString* ustrDirectoryURL ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrDirectoryURL ); + + /* convert directory url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_createDirectory( path ); +} + +/****************************************************************************/ +/* osl_removeDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_removeDirectory( rtl_uString* ustrDirectoryURL ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrDirectoryURL ); + + /* convert directory url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_removeDirectory( path ); +} + +/***************************************** + * osl_psz_createDirectory + ****************************************/ + +static oslFileError osl_psz_createDirectory( const sal_Char* pszPath ) +{ + int nRet=0; + int mode = S_IRWXU | S_IRWXG | S_IRWXO; + + nRet = mkdir(pszPath,mode); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_removeDirectory + ****************************************/ + +static oslFileError osl_psz_removeDirectory( const sal_Char* pszPath ) +{ + int nRet=0; + + nRet = rmdir(pszPath); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_createDirectoryPath */ +/****************************************************************************/ + +static int path_make_parent(sal_Unicode* path) +{ + int i = rtl_ustr_lastIndexOfChar(path, '/'); + + if (i > 0) + { + *(path + i) = 0; + return i; + } + else + return 0; +} + +static int create_dir_with_callback( + sal_Unicode* directory_path, + oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, + void* pData) +{ + int mode = S_IRWXU | S_IRWXG | S_IRWXO; + + if (osl::mkdir(directory_path, mode) == 0) + { + if (aDirectoryCreationCallbackFunc) + { + rtl::OUString url; + osl::FileBase::getFileURLFromSystemPath(directory_path, url); + aDirectoryCreationCallbackFunc(pData, url.pData); + } + return 0; + } + return errno; +} + +static oslFileError create_dir_recursively_( + sal_Unicode* dir_path, + oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, + void* pData) +{ + OSL_PRECOND((rtl_ustr_getLength(dir_path) > 0) && ((dir_path + (rtl_ustr_getLength(dir_path) - 1)) != (dir_path + rtl_ustr_lastIndexOfChar(dir_path, '/'))), \ + "Path must not end with a slash"); + + int native_err = create_dir_with_callback( + dir_path, aDirectoryCreationCallbackFunc, pData); + + if (native_err == 0) + return osl_File_E_None; + + if (native_err != ENOENT) + return oslTranslateFileError(OSL_FET_ERROR, native_err); + + // we step back until '/a_dir' at maximum because + // we should get an error unequal ENOENT when + // we try to create 'a_dir' at '/' and would so + // return before + int pos = path_make_parent(dir_path); + + oslFileError osl_error = create_dir_recursively_( + dir_path, aDirectoryCreationCallbackFunc, pData); + + if (osl_File_E_None != osl_error) + return osl_error; + + dir_path[pos] = '/'; + + return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData); +} + +oslFileError SAL_CALL osl_createDirectoryPath( + rtl_uString* aDirectoryUrl, + oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, + void* pData) +{ + if (aDirectoryUrl == NULL) + return osl_File_E_INVAL; + + rtl::OUString sys_path; + oslFileError osl_error = osl_getSystemPathFromFileURL_Ex( + aDirectoryUrl, &sys_path.pData, sal_False); + + if (osl_error != osl_File_E_None) + return osl_error; + + osl::systemPathRemoveSeparator(sys_path); + + // const_cast because sys_path is a local copy which we want to modify inplace instead of + // coyp it into another buffer on the heap again + return create_dir_recursively_(sys_path.pData->buffer, aDirectoryCreationCallbackFunc, pData); +} + +/****************************************************************************** + * + * C-String Function Declarations + * + *****************************************************************************/ + +static oslFileError osl_psz_removeFile(const sal_Char* pszPath); +static oslFileError osl_psz_copyFile(const sal_Char* pszPath, const sal_Char* pszDestPath); +static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath); + + +/****************************************************************************** + * + * Static Module Utility Function Declarations + * + *****************************************************************************/ + +static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists); +static oslFileError oslChangeFileModes(const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID); +static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName); +static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode); +static oslFileError oslDoMoveFile(const sal_Char* pszPath, const sal_Char* pszDestPath); + +/****************************************************************************/ +/* osl_moveFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_moveFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL ) +{ + char srcPath[PATH_MAX]; + char destPath[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrFileURL ); + OSL_ASSERT( ustrDestURL ); + + /* convert source url to system path */ + eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL ); + if( eRet != osl_File_E_None ) + return eRet; + + /* convert destination url to system path */ + eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return oslDoMoveFile( srcPath, destPath ); +} + +/****************************************************************************/ +/* osl_copyFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_copyFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL ) +{ + char srcPath[PATH_MAX]; + char destPath[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrFileURL ); + OSL_ASSERT( ustrDestURL ); + + /* convert source url to system path */ + eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL ); + if( eRet != osl_File_E_None ) + return eRet; + + /* convert destination url to system path */ + eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_copyFile( srcPath, destPath ); +} + +/****************************************************************************/ +/* osl_removeFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_removeFile( rtl_uString* ustrFileURL ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrFileURL ); + + /* convert file url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrFileURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_removeFile( path ); +} + +/****************************************************************************** + * + * Utility Functions + * + *****************************************************************************/ + +/***************************************** + * oslDoMoveFile + ****************************************/ + +static oslFileError oslDoMoveFile( const sal_Char* pszPath, const sal_Char* pszDestPath) +{ + oslFileError tErr=osl_File_E_invalidError; + + tErr = osl_psz_moveFile(pszPath,pszDestPath); + if ( tErr == osl_File_E_None ) + { + return tErr; + } + + if ( tErr != osl_File_E_XDEV ) + { + return tErr; + } + + tErr=osl_psz_copyFile(pszPath,pszDestPath); + + if ( tErr != osl_File_E_None ) + { + oslFileError tErrRemove; + tErrRemove=osl_psz_removeFile(pszDestPath); + return tErr; + } + + tErr=osl_psz_removeFile(pszPath); + + return tErr; +} + +/***************************************** + * osl_psz_removeFile + ****************************************/ +static oslFileError osl_psz_removeFile( const sal_Char* pszPath ) +{ + int nRet=0; + struct stat aStat; + + nRet = lstat(pszPath,&aStat); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + if ( S_ISDIR(aStat.st_mode) ) + { + return osl_File_E_ISDIR; + } + + nRet = unlink(pszPath); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_moveFile + ****************************************/ + +static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath) +{ + + int nRet = 0; + + nRet = rename(pszPath,pszDestPath); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_copyFile + ****************************************/ + +static oslFileError osl_psz_copyFile( const sal_Char* pszPath, const sal_Char* pszDestPath ) +{ + time_t nAcTime=0; + time_t nModTime=0; + uid_t nUID=0; + gid_t nGID=0; + int nRet=0; + mode_t nMode=0; + struct stat aFileStat; + oslFileError tErr=osl_File_E_invalidError; + size_t nSourceSize=0; + int DestFileExists=1; + + /* mfe: does the source file really exists? */ + nRet = lstat(pszPath,&aFileStat); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + /* mfe: we do only copy files here! */ + if ( S_ISDIR(aFileStat.st_mode) ) + { + return osl_File_E_ISDIR; + } + + nSourceSize=(size_t)aFileStat.st_size; + nMode=aFileStat.st_mode; + nAcTime=aFileStat.st_atime; + nModTime=aFileStat.st_mtime; + nUID=aFileStat.st_uid; + nGID=aFileStat.st_gid; + + nRet = stat(pszDestPath,&aFileStat); + if ( nRet < 0 ) + { + nRet=errno; + + if ( nRet == ENOENT ) + { + DestFileExists=0; + } +/* return oslTranslateFileError(nRet);*/ + } + + /* mfe: the destination file must not be a directory! */ + if ( nRet == 0 && S_ISDIR(aFileStat.st_mode) ) + { + return osl_File_E_ISDIR; + } + else + { + /* mfe: file does not exists or is no dir */ + } + + tErr = oslDoCopy(pszPath,pszDestPath,nMode,nSourceSize,DestFileExists); + + if ( tErr != osl_File_E_None ) + { + return tErr; + } + + /* + * mfe: ignore return code + * since only the success of the copy is + * important + */ + oslChangeFileModes(pszDestPath,nMode,nAcTime,nModTime,nUID,nGID); + + return tErr; +} + + +/****************************************************************************** + * + * Utility Functions + * + *****************************************************************************/ + +/***************************************** + * oslDoCopy + ****************************************/ + +#define TMP_DEST_FILE_EXTENSION ".osl-tmp" + +static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists) +{ + int nRet=0; + sal_Char pszTmpDestFile[PATH_MAX]; + size_t size_tmp_dest_buff = sizeof(pszTmpDestFile); + + /* Quick fix for #106048, the whole copy file function seems + to be erroneous anyway and needs to be rewritten. + Besides osl_copyFile is currently not used from OO/SO code. + */ + memset(pszTmpDestFile, 0, size_tmp_dest_buff); + + if ( DestFileExists ) + { + strncpy(pszTmpDestFile, pszDestFileName, size_tmp_dest_buff - 1); + + if ((strlen(pszTmpDestFile) + strlen(TMP_DEST_FILE_EXTENSION)) >= size_tmp_dest_buff) + return osl_File_E_NAMETOOLONG; + + strncat(pszTmpDestFile, TMP_DEST_FILE_EXTENSION, strlen(TMP_DEST_FILE_EXTENSION)); + + /* FIXME: what if pszTmpDestFile already exists? */ + /* with getcanonical??? */ + nRet=rename(pszDestFileName,pszTmpDestFile); + } + + /* mfe: should be S_ISREG */ + if ( !S_ISLNK(nMode) ) + { + /* copy SourceFile to DestFile */ + nRet = oslDoCopyFile(pszSourceFileName,pszDestFileName,nSourceSize, nMode); + } + /* mfe: OK redundant at the moment */ + else if ( S_ISLNK(nMode) ) + { + nRet = oslDoCopyLink(pszSourceFileName,pszDestFileName); + } + else + { + /* mfe: what to do here? */ + nRet=ENOSYS; + } + + if ( nRet > 0 && DestFileExists == 1 ) + { + unlink(pszDestFileName); + rename(pszTmpDestFile,pszDestFileName); + } + + if ( nRet > 0 ) + { + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + if ( DestFileExists == 1 ) + { + unlink(pszTmpDestFile); + } + + return osl_File_E_None; +} + +/***************************************** + * oslChangeFileModes + ****************************************/ + +static oslFileError oslChangeFileModes( const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID) +{ + int nRet=0; + struct utimbuf aTimeBuffer; + + nRet = chmod(pszFileName,nMode); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + aTimeBuffer.actime=nAcTime; + aTimeBuffer.modtime=nModTime; + nRet=utime(pszFileName,&aTimeBuffer); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + if ( nUID != getuid() ) + { + nUID=getuid(); + } + + nRet=chown(pszFileName,nUID,nGID); + if ( nRet < 0 ) + { + nRet=errno; + + /* mfe: do not return an error here! */ + /* return oslTranslateFileError(nRet);*/ + } + + return osl_File_E_None; +} + +/***************************************** + * oslDoCopyLink + ****************************************/ + +static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName) +{ + int nRet=0; + + /* mfe: if dest file is symbolic link remove the link and place the file instead (hro says so) */ + /* mfe: if source is a link copy the link and not the file it points to (hro says so) */ + sal_Char pszLinkContent[PATH_MAX]; + + pszLinkContent[0] = '\0'; + + nRet = readlink(pszSourceFileName,pszLinkContent,PATH_MAX); + + if ( nRet < 0 ) + { + nRet=errno; + return nRet; + } + else + pszLinkContent[ nRet ] = 0; + + nRet = symlink(pszLinkContent,pszDestFileName); + + if ( nRet < 0 ) + { + nRet=errno; + return nRet; + } + + return 0; +} + +/***************************************** + * oslDoCopyFile + ****************************************/ + +static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode) +{ + int SourceFileFD=0; + int DestFileFD=0; + int nRet=0; + + SourceFileFD=open(pszSourceFileName,O_RDONLY); + if ( SourceFileFD < 0 ) + { + nRet=errno; + return nRet; + } + + DestFileFD=open(pszDestFileName, O_WRONLY | O_CREAT, mode); + + if ( DestFileFD < 0 ) + { + nRet=errno; + close(SourceFileFD); + return nRet; + } + + /* HACK: because memory mapping fails on various + platforms if the size of the source file is 0 byte */ + if (0 == nSourceSize) + { + close(SourceFileFD); + close(DestFileFD); + return 0; + } + + // read and lseek are used to check the possibility to access the data + // not a nice solution, but it allows to avoid a crash in case it is an opened samba file + // generally, reading of one byte should not affect the performance + char nCh; + if ( 1 != read( SourceFileFD, &nCh, 1 ) + || -1 == lseek( SourceFileFD, 0, SEEK_SET ) ) + { + nRet = errno; + close( SourceFileFD ); + close( DestFileFD ); + return nRet; + } + + size_t nWritten = 0; + size_t nRemains = nSourceSize; + + /* mmap file -- open dest file -- write -- fsync it at the end */ + void* pSourceFile = mmap( 0, nSourceSize, PROT_READ, MAP_SHARED, SourceFileFD, 0 ); + if ( pSourceFile != MAP_FAILED ) + { + nWritten = write( DestFileFD, pSourceFile, nSourceSize ); + nRemains -= nWritten; + munmap( (char*)pSourceFile, nSourceSize ); + } + + if ( nRemains ) + { + /* mmap has problems, try the direct streaming */ + char pBuffer[32000]; + size_t nRead = 0; + + nRemains = nSourceSize; + + if ( -1 != lseek( SourceFileFD, 0, SEEK_SET ) + && -1 != lseek( DestFileFD, 0, SEEK_SET ) ) + { + do + { + nRead = 0; + nWritten = 0; + + size_t nToRead = std::min( (size_t)32000, nRemains ); + nRead = read( SourceFileFD, pBuffer, nToRead ); + if ( (size_t)-1 != nRead ) + nWritten = write( DestFileFD, pBuffer, nRead ); + + if ( (size_t)-1 != nWritten ) + nRemains -= nWritten; + } + while( nRemains && (size_t)-1 != nRead && nRead == nWritten ); + } + } + + if ( nRemains ) + { + if ( errno ) + nRet = errno; + else + nRet = ENOSPC; + } + + close( SourceFileFD ); + if ( close( DestFileFD ) == -1 && nRet == 0 ) + nRet = errno; + + return nRet; +} + diff --git a/sal/osl/unx/file_path_helper.cxx b/sal/osl/unx/file_path_helper.cxx new file mode 100644 index 000000000000..04fdd13e7c15 --- /dev/null +++ b/sal/osl/unx/file_path_helper.cxx @@ -0,0 +1,350 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + + /******************************************* + Includes + ******************************************/ + + #ifndef _OSL_FILE_PATH_HELPER_H_ + #include "file_path_helper.h" + #endif + + #ifndef _OSL_FILE_PATH_HELPER_HXX_ + #include "file_path_helper.hxx" + #endif + + #ifndef _OSL_UUNXAPI_HXX_ + #include "uunxapi.hxx" + #endif + + #ifndef _OSL_DIAGNOSE_H_ + #include <osl/diagnose.h> + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + /******************************************* + Constants + ******************************************/ + + const sal_Unicode FPH_CHAR_PATH_SEPARATOR = (sal_Unicode)'/'; + const sal_Unicode FPH_CHAR_DOT = (sal_Unicode)'.'; + const sal_Unicode FPH_CHAR_COLON = (sal_Unicode)':'; + + inline const rtl::OUString FPH_PATH_SEPARATOR() + { return rtl::OUString::createFromAscii("/"); } + inline const rtl::OUString FPH_LOCAL_DIR_ENTRY() + { return rtl::OUString::createFromAscii("."); } + inline const rtl::OUString FPH_PARENT_DIR_ENTRY() + { return rtl::OUString::createFromAscii(".."); } + + /******************************************* + * osl_systemPathRemoveSeparator + ******************************************/ + + void SAL_CALL osl_systemPathRemoveSeparator(rtl_uString* pustrPath) + { + OSL_PRECOND(pustrPath, "osl_systemPathRemoveSeparator: Invalid parameter"); + + // maybe there are more than one separator at end + // so we run in a loop + while ((pustrPath->length > 1) && (FPH_CHAR_PATH_SEPARATOR == pustrPath->buffer[pustrPath->length - 1])) + { + pustrPath->length--; + pustrPath->buffer[pustrPath->length] = (sal_Unicode)'\0'; + } + + OSL_POSTCOND((0 == pustrPath->length) || (1 == pustrPath->length) || \ + (pustrPath->length > 1 && pustrPath->buffer[pustrPath->length - 1] != FPH_CHAR_PATH_SEPARATOR), \ + "osl_systemPathRemoveSeparator: Post condition failed"); + } + + /******************************************* + osl_systemPathEnsureSeparator + ******************************************/ + + void SAL_CALL osl_systemPathEnsureSeparator(rtl_uString** ppustrPath) + { + OSL_PRECOND(ppustrPath && (NULL != *ppustrPath), \ + "osl_systemPathEnsureSeparator: Invalid parameter"); + + rtl::OUString path(*ppustrPath); + sal_Int32 lp = path.getLength(); + sal_Int32 i = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR); + + if ((lp > 1 && i != (lp - 1)) || ((lp < 2) && i < 0)) + { + path += FPH_PATH_SEPARATOR(); + rtl_uString_assign(ppustrPath, path.pData); + } + + OSL_POSTCOND(path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR) == (path.getLength() - 1), \ + "osl_systemPathEnsureSeparator: Post condition failed"); + } + + /******************************************* + * osl_systemPathIsRelativePath + ******************************************/ + + sal_Bool SAL_CALL osl_systemPathIsRelativePath(const rtl_uString* pustrPath) + { + OSL_PRECOND(pustrPath, "osl_systemPathIsRelativePath: Invalid parameter"); + return ((0 == pustrPath->length) || (pustrPath->buffer[0] != FPH_CHAR_PATH_SEPARATOR)); + } + + /****************************************** + osl_systemPathMakeAbsolutePath + *****************************************/ + + void SAL_CALL osl_systemPathMakeAbsolutePath( + const rtl_uString* pustrBasePath, + const rtl_uString* pustrRelPath, + rtl_uString** ppustrAbsolutePath) +{ + rtl::OUString base(rtl_uString_getStr(const_cast<rtl_uString*>(pustrBasePath))); + rtl::OUString rel(const_cast<rtl_uString*>(pustrRelPath)); + + if (base.getLength() > 0) + osl_systemPathEnsureSeparator(&base.pData); + + base += rel; + + rtl_uString_acquire(base.pData); + *ppustrAbsolutePath = base.pData; +} + + + /******************************************* + osl_systemPathGetFileOrLastDirectoryPart + ******************************************/ + + void SAL_CALL osl_systemPathGetFileNameOrLastDirectoryPart( + const rtl_uString* pustrPath, + rtl_uString** ppustrFileNameOrLastDirPart) +{ + OSL_PRECOND(pustrPath && ppustrFileNameOrLastDirPart, \ + "osl_systemPathGetFileNameOrLastDirectoryPart: Invalid parameter"); + + rtl::OUString path(const_cast<rtl_uString*>(pustrPath)); + + osl_systemPathRemoveSeparator(path.pData); + + rtl::OUString last_part; + + if (path.getLength() > 1 || (1 == path.getLength() && *path.getStr() != FPH_CHAR_PATH_SEPARATOR)) + { + sal_Int32 idx_ps = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR); + idx_ps++; // always right to increment by one even if idx_ps == -1! + last_part = rtl::OUString(path.getStr() + idx_ps); + } + rtl_uString_assign(ppustrFileNameOrLastDirPart, last_part.pData); +} + + + /******************************************** + osl_systemPathIsHiddenFileOrDirectoryEntry + *********************************************/ + + sal_Bool SAL_CALL osl_systemPathIsHiddenFileOrDirectoryEntry( + const rtl_uString* pustrPath) +{ + OSL_PRECOND(pustrPath, "osl_systemPathIsHiddenFileOrDirectoryEntry: Invalid parameter"); + + sal_Bool is_hidden = sal_False; + + if (pustrPath->length > 0) + { + rtl::OUString fdp; + + osl_systemPathGetFileNameOrLastDirectoryPart(pustrPath, &fdp.pData); + + is_hidden = ((fdp.pData->length > 0) && (fdp.pData->buffer[0] == FPH_CHAR_DOT) && + !osl_systemPathIsLocalOrParentDirectoryEntry(fdp.pData)); + } + + return is_hidden; +} + + + /************************************************ + osl_systemPathIsLocalOrParentDirectoryEntry + ************************************************/ + +sal_Bool SAL_CALL osl_systemPathIsLocalOrParentDirectoryEntry( + const rtl_uString* pustrPath) +{ + OSL_PRECOND(pustrPath, "osl_systemPathIsLocalOrParentDirectoryEntry: Invalid parameter"); + + rtl::OUString dirent; + + osl_systemPathGetFileNameOrLastDirectoryPart(pustrPath, &dirent.pData); + + return ( + (dirent == FPH_LOCAL_DIR_ENTRY()) || + (dirent == FPH_PARENT_DIR_ENTRY()) + ); +} + +/*********************************************** + Simple iterator for a path list separated by + the specified character + **********************************************/ + +class path_list_iterator +{ +public: + + /****************************************** + constructor + + after construction get_current_item + returns the first path in list, no need + to call reset first + *****************************************/ + path_list_iterator(const rtl::OUString& path_list, sal_Unicode list_separator = FPH_CHAR_COLON) : + m_path_list(path_list), + m_end(m_path_list.getStr() + m_path_list.getLength() + 1), + m_separator(list_separator) + { + reset(); + } + + /****************************************** + reset the iterator + *****************************************/ + void reset() + { + m_path_segment_begin = m_path_segment_end = m_path_list.getStr(); + advance(); + } + + /****************************************** + move the iterator to the next position + *****************************************/ + void next() + { + OSL_PRECOND(!done(), "path_list_iterator: Already done!"); + + m_path_segment_begin = ++m_path_segment_end; + advance(); + } + + /****************************************** + check if done + *****************************************/ + bool done() const + { + return (m_path_segment_end >= m_end); + } + + /****************************************** + return the current item + *****************************************/ + rtl::OUString get_current_item() const + { + return rtl::OUString( + m_path_segment_begin, + (m_path_segment_end - m_path_segment_begin)); + } + +private: + + /****************************************** + move m_path_end to the next separator or + to the edn of the string + *****************************************/ + void advance() + { + while (!done() && *m_path_segment_end && (*m_path_segment_end != m_separator)) + ++m_path_segment_end; + + OSL_ASSERT(m_path_segment_end <= m_end); + } + +private: + rtl::OUString m_path_list; + const sal_Unicode* m_end; + const sal_Unicode m_separator; + const sal_Unicode* m_path_segment_begin; + const sal_Unicode* m_path_segment_end; + +// prevent copy and assignment +private: + /****************************************** + copy constructor + remember: do not simply copy m_path_begin + and m_path_end because they point to + the memory of other.m_path_list! + *****************************************/ + path_list_iterator(const path_list_iterator& other); + + /****************************************** + assignment operator + remember: do not simply copy m_path_begin + and m_path_end because they point to + the memory of other.m_path_list! + *****************************************/ + path_list_iterator& operator=(const path_list_iterator& other); +}; + + /************************************************ + osl_searchPath + ***********************************************/ + +sal_Bool SAL_CALL osl_searchPath( + const rtl_uString* pustrFilePath, + const rtl_uString* pustrSearchPathList, + rtl_uString** ppustrPathFound) +{ + OSL_PRECOND(pustrFilePath && pustrSearchPathList && ppustrPathFound, "osl_searchPath: Invalid parameter"); + + bool bfound = false; + rtl::OUString fp(const_cast<rtl_uString*>(pustrFilePath)); + rtl::OUString pl = rtl::OUString(const_cast<rtl_uString*>(pustrSearchPathList)); + path_list_iterator pli(pl); + + while (!pli.done()) + { + rtl::OUString p = pli.get_current_item(); + osl::systemPathEnsureSeparator(p); + p += fp; + + if (osl::access(p, F_OK) > -1) + { + bfound = true; + rtl_uString_assign(ppustrPathFound, p.pData); + break; + } + pli.next(); + } + return bfound; +} diff --git a/sal/osl/unx/file_path_helper.h b/sal/osl/unx/file_path_helper.h new file mode 100644 index 000000000000..c1e3908fa9f2 --- /dev/null +++ b/sal/osl/unx/file_path_helper.h @@ -0,0 +1,247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_FILE_PATH_HELPER_H_ + #define _OSL_FILE_PATH_HELPER_H_ + + + #ifndef _SAL_TYPES_H_ + #include <sal/types.h> + #endif + + #ifndef _RTL_USTRING_H_ + #include <rtl/ustring.h> + #endif + + + #ifdef __cplusplus + extern "C" + { + #endif + + + /******************************************* + osl_systemPathRemoveSeparator + Removes the last separator from the + given system path if any and if the path + is not the root path '/' + + @param ppustrPath [inout] a system path + if the path is not the root path + and the last character is a + path separator it will be cut off + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + void SAL_CALL osl_systemPathRemoveSeparator( + /*inout*/ rtl_uString* pustrPath); + + /******************************************* + osl_systemPathEnsureSeparator + Adds a trailing path separator to the + given system path if not already there + and if the path is not the root path '/' + + @param pustrPath [inout] a system path + if the path is not the root path + '/' and has no trailing separator + a separator will be added + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + void SAL_CALL osl_systemPathEnsureSeparator( + /*inout*/ rtl_uString** ppustrPath); + + /******************************************* + osl_systemPathIsRelativePath + Returns true if the given path is a + relative path and so starts not with '/' + + @param pustrPath [in] a system path + pustrPath must not be NULL + + @returns sal_True if the given path + doesn't start with a separator + else sal_False will be returned + + ******************************************/ + + sal_Bool SAL_CALL osl_systemPathIsRelativePath( + const rtl_uString* pustrPath); + + /****************************************** + osl_systemPathMakeAbsolutePath + Append a relative path to a base path + + @param pustrBasePath [in] a system + path that will be considered as + base path + pustrBasePath must not be NULL + + @param pustrRelPath [in] a system path + that will be considered as + relative path + pustrBasePath must not be NULL + + @param ppustrAbsolutePath [out] the + resulting path which is a + concatination of the base and + the relative path + if base path is empty the + resulting absolute path is the + relative path + if relative path is empty the + resulting absolute path is the + base path + if base and relative path are + empty the resulting absolute + path is also empty + ppustrAbsolutePath must not be + NULL and *ppustrAbsolutePath + must be 0 or point to a valid + rtl_uString + + *****************************************/ + + void SAL_CALL osl_systemPathMakeAbsolutePath( + const rtl_uString* pustrBasePath, + const rtl_uString* pustrRelPath, + rtl_uString** ppustrAbsolutePath); + + /***************************************** + osl_systemPathGetFileOrLastDirectoryPart + Returns the file or the directory part + of the given path + + @param pustrPath [in] a system path, + must not be NULL + + @param ppustrFileOrDirPart [out] on + return receives the last part + of the given directory or the + file name + if pustrPath is the root path + '/' an empty string will be + returned + if pustrPath has a trailing + '/' the last part before the + '/' will be returned else + the part after the last '/' + will be returned + + @returns nothing + + ****************************************/ + void SAL_CALL osl_systemPathGetFileNameOrLastDirectoryPart( + const rtl_uString* pustrPath, + rtl_uString** ppustrFileNameOrLastDirPart); + + + /******************************************** + osl_systemPathIsHiddenFileOrDirectoryEntry + Returns sal_True if the last part of + given system path is not '.' or '..' + alone and starts with a '.' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of + the given system path starts + with '.' or sal_False the last + part is '.' or '..' alone or + doesn't start with a dot + + *********************************************/ + + sal_Bool SAL_CALL osl_systemPathIsHiddenFileOrDirectoryEntry( + const rtl_uString* pustrPath); + + + /************************************************ + osl_systemPathIsLocalOrParentDirectoryEntry + Returns sal_True if the last part of the given + system path is the local directory entry '.' + or the parent directory entry '..' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of the + given system path is '.' or '..' + else sal_False + + ************************************************/ + + sal_Bool SAL_CALL osl_systemPathIsLocalOrParentDirectoryEntry( + const rtl_uString* pustrPath); + + + /************************************************ + osl_searchPath + Searches for a file name or path name in all + directories specified by a given path list. + Symbolic links in the resulting path will not be + resolved, it's up to the caller to do this. + + @param pustrFilePath [in] a file name or + directory name to search for, the name must + be provided as system path not as a file URL + + @param pustrSearchPathList [in] a ':' + separated list of paths in which to search for + the file or directory name + + @ppustrPathFound [out] on success receives the + complete path of the file or directory found + as a system path + + @returns sal_True if the specified file or + directory was found else sal_False + ***********************************************/ + + sal_Bool SAL_CALL osl_searchPath( + const rtl_uString* pustrFilePath, + const rtl_uString* pustrSearchPathList, + rtl_uString** ppustrPathFound); + + + #ifdef __cplusplus + } + #endif + + + #endif /* #ifndef _OSL_PATH_HELPER_H_ */ + diff --git a/sal/osl/unx/file_path_helper.hxx b/sal/osl/unx/file_path_helper.hxx new file mode 100644 index 000000000000..4b429b111799 --- /dev/null +++ b/sal/osl/unx/file_path_helper.hxx @@ -0,0 +1,247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_FILE_PATH_HELPER_HXX_ +#define _OSL_FILE_PATH_HELPER_HXX_ + + +#ifndef _OSL_FILE_PATH_HELPER_H_ +#include "file_path_helper.h" +#endif + +#include <rtl/ustring.hxx> + + +namespace osl +{ + + /******************************************* + systemPathRemoveSeparator + Removes the last separator from the + given system path if any and if the path + is not the root path '/' + + @param ppustrPath [inout] a system path + if the path is not the root path + and the last character is a + path separator it will be cut off + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + inline void systemPathRemoveSeparator(/*inout*/ rtl::OUString& Path) + { + osl_systemPathRemoveSeparator(Path.pData); + } + + /******************************************* + systemPathEnsureSeparator + Adds a trailing path separator to the + given system path if not already there + and if the path is not the root path '/' + + @param pustrPath [inout] a system path + if the path is not the root path + '/' and has no trailing separator + a separator will be added + ppustrPath must not be NULL and + must point to a valid rtl_uString + + @returns nothing + + ******************************************/ + + inline void systemPathEnsureSeparator(/*inout*/ rtl::OUString& Path) + { + osl_systemPathEnsureSeparator(&Path.pData); + } + + /******************************************* + systemPathIsRelativePath + Returns true if the given path is a + relative path and so starts not with '/' + + @param pustrPath [in] a system path + pustrPath must not be NULL + + @returns sal_True if the given path + doesn't start with a separator + else sal_False will be returned + + ******************************************/ + + inline bool systemPathIsRelativePath(const rtl::OUString& Path) + { + return osl_systemPathIsRelativePath(Path.pData); + } + + /****************************************** + systemPathMakeAbsolutePath + Append a relative path to a base path + + @param pustrBasePath [in] a system + path that will be considered as + base path + pustrBasePath must not be NULL + + @param pustrRelPath [in] a system path + that will be considered as + relative path + pustrBasePath must not be NULL + + @param ppustrAbsolutePath [out] the + resulting path which is a + concatination of the base and + the relative path + if base path is empty the + resulting absolute path is the + relative path + if relative path is empty the + resulting absolute path is the + base path + if base and relative path are + empty the resulting absolute + path is also empty + ppustrAbsolutePath must not be + NULL and *ppustrAbsolutePath + must be 0 or point to a valid + rtl_uString + + *****************************************/ + + inline void systemPathMakeAbsolutePath( + const rtl::OUString& BasePath, + const rtl::OUString& RelPath, + rtl::OUString& AbsolutePath) + { + osl_systemPathMakeAbsolutePath( + BasePath.pData, RelPath.pData, &AbsolutePath.pData); + } + + /***************************************** + systemPathGetFileOrLastDirectoryPart + Returns the file or the directory part + of the given path + + @param pustrPath [in] a system path, + must not be NULL + + @param ppustrFileOrDirPart [out] on + return receives the last part + of the given directory or the + file name + if pustrPath is the root path + '/' an empty string will be + returned + if pustrPath has a trailing + '/' the last part before the + '/' will be returned else + the part after the last '/' + will be returned + + @returns nothing + + ****************************************/ + + inline void systemPathGetFileNameOrLastDirectoryPart( + const rtl::OUString& Path, + rtl::OUString& FileNameOrLastDirPart) + { + osl_systemPathGetFileNameOrLastDirectoryPart( + Path.pData, &FileNameOrLastDirPart.pData); + } + + + /******************************************** + systemPathIsHiddenFileOrDirectoryEntry + Returns sal_True if the last part of + given system path is not '.' or '..' + alone and starts with a '.' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of + the given system path starts + with '.' or sal_False the last + part is '.' or '..' alone or + doesn't start with a dot + + *********************************************/ + + inline bool systemPathIsHiddenFileOrDirectoryEntry( + const rtl::OUString& Path) + { + return osl_systemPathIsHiddenFileOrDirectoryEntry(Path.pData); + } + + + /************************************************ + systemPathIsLocalOrParentDirectoryEntry + Returns sal_True if the last part of the given + system path is the local directory entry '.' + or the parent directory entry '..' + + @param pustrPath [in] a system path, + must not be NULL + + @returns sal_True if the last part of the + given system path is '.' or '..' + else sal_False + + ************************************************/ + + inline bool systemPathIsLocalOrParentDirectoryEntry( + const rtl::OUString& Path) + { + return osl_systemPathIsLocalOrParentDirectoryEntry(Path.pData); + } + + /************************************************ + searchPath + ***********************************************/ + + inline bool searchPath( + const rtl::OUString& ustrFilePath, + const rtl::OUString& ustrSearchPathList, + rtl::OUString& ustrPathFound) + { + return osl_searchPath( + ustrFilePath.pData, + ustrSearchPathList.pData, + &ustrPathFound.pData); + } + + + } // namespace osl + + + #endif /* #ifndef _OSL_PATH_HELPER_HXX_ */ + diff --git a/sal/osl/unx/file_stat.cxx b/sal/osl/unx/file_stat.cxx new file mode 100644 index 000000000000..df32fa105a50 --- /dev/null +++ b/sal/osl/unx/file_stat.cxx @@ -0,0 +1,492 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "osl/file.h" + +#include "system.h" +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <limits.h> +#include <unistd.h> + +#include "file_impl.hxx" +#include "file_error_transl.h" +#include "file_path_helper.hxx" +#include "file_url.h" +#include "uunxapi.hxx" + +namespace /* private */ +{ + + inline void set_file_type(const struct stat& file_stat, oslFileStatus* pStat) + { + /* links to directories state also to be a directory */ + if (S_ISLNK(file_stat.st_mode)) + pStat->eType = osl_File_Type_Link; + else if (S_ISDIR(file_stat.st_mode)) + pStat->eType = osl_File_Type_Directory; + else if (S_ISREG(file_stat.st_mode)) + pStat->eType = osl_File_Type_Regular; + else if (S_ISFIFO(file_stat.st_mode)) + pStat->eType = osl_File_Type_Fifo; + else if (S_ISSOCK(file_stat.st_mode)) + pStat->eType = osl_File_Type_Socket; + else if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode)) + pStat->eType = osl_File_Type_Special; + else + pStat->eType = osl_File_Type_Unknown; + + pStat->uValidFields |= osl_FileStatus_Mask_Type; + } + + inline void set_file_access_mask(const struct stat& file_stat, oslFileStatus* pStat) + { + // user permissions + if (S_IRUSR & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OwnRead; + + if (S_IWUSR & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OwnWrite; + + if (S_IXUSR & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OwnExe; + + // group permissions + if (S_IRGRP & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_GrpRead; + + if (S_IWGRP & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_GrpWrite; + + if (S_IXGRP & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_GrpExe; + + // others permissions + if (S_IROTH & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OthRead; + + if (S_IWOTH & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OthWrite; + + if (S_IXOTH & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_OthExe; + + pStat->uValidFields |= osl_FileStatus_Mask_Attributes; + } + + inline void set_file_access_rights(const struct stat& file_stat, int S_IR, int S_IW, int S_IX, oslFileStatus* pStat) + { + /* we cannot really map osl_File_Attribute_ReadOnly to + the Unix access rights, it's a Windows only flag + that's why the following hack. We set osl_FileStatus_Mask_Attributes + but if there is no read access for a file we clear the flag + again to signal to the caller that there are no file attributes + to read because that's better than to give them incorrect one. + */ + pStat->uValidFields |= osl_FileStatus_Mask_Attributes; + + if ((0 == (S_IW & file_stat.st_mode)) && (S_IR & file_stat.st_mode)) + pStat->uAttributes |= osl_File_Attribute_ReadOnly; + + if (S_IX & file_stat.st_mode) + pStat->uAttributes |= osl_File_Attribute_Executable; + } + + /* a process may belong to up to NGROUPS_MAX groups, so when + checking group access rights, we have to check all belonging + groups */ + inline bool is_in_process_grouplist(const gid_t file_group) + { + // check primary process group + + if (getgid() == file_group) + return true; + + // check supplementary process groups + + gid_t grplist[NGROUPS_MAX]; + int grp_number = getgroups(NGROUPS_MAX, grplist); + + for (int i = 0; i < grp_number; i++) + { + if (grplist[i] == file_group) + return true; + } + return false; + } + + /* Currently we are determining the file access right based + on the real user ID not the effective user ID! + We don't use access(...) because access follows links which + may cause performance problems see #97133. + */ + inline void set_file_access_rights(const struct stat& file_stat, oslFileStatus* pStat) + { + if (getuid() == file_stat.st_uid) + { + set_file_access_rights(file_stat, S_IRUSR, S_IWUSR, S_IXUSR, pStat); + } + else if (is_in_process_grouplist(file_stat.st_gid)) + { + set_file_access_rights(file_stat, S_IRGRP, S_IWGRP, S_IXGRP, pStat); + } + else + { + set_file_access_rights(file_stat, S_IROTH, S_IWOTH, S_IXOTH, pStat); + } + } + + inline void set_file_hidden_status(const rtl::OUString& file_path, oslFileStatus* pStat) + { + pStat->uAttributes = osl::systemPathIsHiddenFileOrDirectoryEntry(file_path) ? osl_File_Attribute_Hidden : 0; + pStat->uValidFields |= osl_FileStatus_Mask_Attributes; + } + + /* the set_file_access_rights must be called after set_file_hidden_status(...) and + set_file_access_mask(...) because of the hack in set_file_access_rights(...) */ + inline void set_file_attributes( + const rtl::OUString& file_path, const struct stat& file_stat, const sal_uInt32 uFieldMask, oslFileStatus* pStat) + { + set_file_hidden_status(file_path, pStat); + set_file_access_mask(file_stat, pStat); + + // we set the file access rights only on demand + // because it's potentially expensive + if (uFieldMask & osl_FileStatus_Mask_Attributes) + set_file_access_rights(file_stat, pStat); + } + + inline void set_file_access_time(const struct stat& file_stat, oslFileStatus* pStat) + { + pStat->aAccessTime.Seconds = file_stat.st_atime; + pStat->aAccessTime.Nanosec = 0; + pStat->uValidFields |= osl_FileStatus_Mask_AccessTime; + } + + inline void set_file_modify_time(const struct stat& file_stat, oslFileStatus* pStat) + { + pStat->aModifyTime.Seconds = file_stat.st_mtime; + pStat->aModifyTime.Nanosec = 0; + pStat->uValidFields |= osl_FileStatus_Mask_ModifyTime; + } + + inline void set_file_size(const struct stat& file_stat, oslFileStatus* pStat) + { + if (S_ISREG(file_stat.st_mode)) + { + pStat->uFileSize = file_stat.st_size; + pStat->uValidFields |= osl_FileStatus_Mask_FileSize; + } + } + + /* we only need to call stat or lstat if one of the + following flags is set */ + inline bool is_stat_call_necessary(sal_uInt32 field_mask, oslFileType file_type = osl_File_Type_Unknown) + { + return ( + ((field_mask & osl_FileStatus_Mask_Type) && (file_type == osl_File_Type_Unknown)) || + (field_mask & osl_FileStatus_Mask_Attributes) || + (field_mask & osl_FileStatus_Mask_CreationTime) || + (field_mask & osl_FileStatus_Mask_AccessTime) || + (field_mask & osl_FileStatus_Mask_ModifyTime) || + (field_mask & osl_FileStatus_Mask_FileSize) || + (field_mask & osl_FileStatus_Mask_LinkTargetURL) || + (field_mask & osl_FileStatus_Mask_Validate)); + } + + inline oslFileError set_link_target_url(const rtl::OUString& file_path, oslFileStatus* pStat) + { + rtl::OUString link_target; + if (!osl::realpath(file_path, link_target)) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + oslFileError osl_error = osl_getFileURLFromSystemPath(link_target.pData, &pStat->ustrLinkTargetURL); + if (osl_error != osl_File_E_None) + return osl_error; + + pStat->uValidFields |= osl_FileStatus_Mask_LinkTargetURL; + return osl_File_E_None; + } + + inline oslFileError setup_osl_getFileStatus( + DirectoryItem_Impl * pImpl, oslFileStatus* pStat, rtl::OUString& file_path) + { + if ((NULL == pImpl) || (NULL == pStat)) + return osl_File_E_INVAL; + + file_path = rtl::OUString(pImpl->m_ustrFilePath); + OSL_ASSERT(file_path.getLength() > 0); + if (file_path.getLength() <= 0) + return osl_File_E_INVAL; + + pStat->uValidFields = 0; + return osl_File_E_None; + } + +} // end namespace private + + +/**************************************************************************** + * osl_getFileStatus + ****************************************************************************/ + +oslFileError SAL_CALL osl_getFileStatus(oslDirectoryItem Item, oslFileStatus* pStat, sal_uInt32 uFieldMask) +{ + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item); + + rtl::OUString file_path; + oslFileError osl_error = setup_osl_getFileStatus(pImpl, pStat, file_path); + if (osl_File_E_None != osl_error) + return osl_error; + +#if defined(__GNUC__) && (__GNUC__ < 3) + struct ::stat file_stat; +#else + struct stat file_stat; +#endif + + bool bStatNeeded = is_stat_call_necessary(uFieldMask, pImpl->getFileType()); + if (bStatNeeded && (0 != osl::lstat(file_path, file_stat))) + return oslTranslateFileError(OSL_FET_ERROR, errno); + + if (bStatNeeded) + { + // we set all these attributes because it's cheap + set_file_type(file_stat, pStat); + set_file_access_time(file_stat, pStat); + set_file_modify_time(file_stat, pStat); + set_file_size(file_stat, pStat); + set_file_attributes(file_path, file_stat, uFieldMask, pStat); + + // file exists semantic of osl_FileStatus_Mask_Validate + if ((uFieldMask & osl_FileStatus_Mask_LinkTargetURL) && S_ISLNK(file_stat.st_mode)) + { + osl_error = set_link_target_url(file_path, pStat); + if (osl_error != osl_File_E_None) + return osl_error; + } + } +#ifdef _DIRENT_HAVE_D_TYPE + else if (uFieldMask & osl_FileStatus_Mask_Type) + { + pStat->eType = pImpl->getFileType(); + pStat->uValidFields |= osl_FileStatus_Mask_Type; + } +#endif /* _DIRENT_HAVE_D_TYPE */ + + if (uFieldMask & osl_FileStatus_Mask_FileURL) + { + if ((osl_error = osl_getFileURLFromSystemPath(file_path.pData, &pStat->ustrFileURL)) != osl_File_E_None) + return osl_error; + + pStat->uValidFields |= osl_FileStatus_Mask_FileURL; + } + + if (uFieldMask & osl_FileStatus_Mask_FileName) + { + osl_systemPathGetFileNameOrLastDirectoryPart(file_path.pData, &pStat->ustrFileName); + pStat->uValidFields |= osl_FileStatus_Mask_FileName; + } + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_setFileAttributes */ +/****************************************************************************/ + +static oslFileError osl_psz_setFileAttributes( const sal_Char* pszFilePath, sal_uInt64 uAttributes ) +{ + oslFileError osl_error = osl_File_E_None; + mode_t nNewMode = 0; + + OSL_ENSURE(!(osl_File_Attribute_Hidden & uAttributes), "osl_File_Attribute_Hidden doesn't work under Unix"); + + if (uAttributes & osl_File_Attribute_OwnRead) + nNewMode |= S_IRUSR; + + if (uAttributes & osl_File_Attribute_OwnWrite) + nNewMode|=S_IWUSR; + + if (uAttributes & osl_File_Attribute_OwnExe) + nNewMode|=S_IXUSR; + + if (uAttributes & osl_File_Attribute_GrpRead) + nNewMode|=S_IRGRP; + + if (uAttributes & osl_File_Attribute_GrpWrite) + nNewMode|=S_IWGRP; + + if (uAttributes & osl_File_Attribute_GrpExe) + nNewMode|=S_IXGRP; + + if (uAttributes & osl_File_Attribute_OthRead) + nNewMode|=S_IROTH; + + if (uAttributes & osl_File_Attribute_OthWrite) + nNewMode|=S_IWOTH; + + if (uAttributes & osl_File_Attribute_OthExe) + nNewMode|=S_IXOTH; + + if (chmod(pszFilePath, nNewMode) < 0) + osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); + + return osl_error; +} + +oslFileError SAL_CALL osl_setFileAttributes( rtl_uString* ustrFileURL, sal_uInt64 uAttributes ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrFileURL ); + + /* convert file url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrFileURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_setFileAttributes( path, uAttributes ); +} + +/****************************************************************************/ +/* osl_setFileTime */ +/****************************************************************************/ + +static oslFileError osl_psz_setFileTime ( + const sal_Char* pszFilePath, + const TimeValue* /*pCreationTime*/, + const TimeValue* pLastAccessTime, + const TimeValue* pLastWriteTime ) +{ + int nRet=0; + struct utimbuf aTimeBuffer; + struct stat aFileStat; +#ifdef DEBUG_OSL_FILE + struct tm* pTM=0; +#endif + + nRet = lstat(pszFilePath,&aFileStat); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"File Times are (in localtime):\n"); + pTM=localtime(&aFileStat.st_ctime); + fprintf(stderr,"CreationTime is '%s'\n",asctime(pTM)); + pTM=localtime(&aFileStat.st_atime); + fprintf(stderr,"AccessTime is '%s'\n",asctime(pTM)); + pTM=localtime(&aFileStat.st_mtime); + fprintf(stderr,"Modification is '%s'\n",asctime(pTM)); + + fprintf(stderr,"File Times are (in UTC):\n"); + fprintf(stderr,"CreationTime is '%s'\n",ctime(&aFileStat.st_ctime)); + fprintf(stderr,"AccessTime is '%s'\n",ctime(&aTimeBuffer.actime)); + fprintf(stderr,"Modification is '%s'\n",ctime(&aTimeBuffer.modtime)); +#endif + + if ( pLastAccessTime != 0 ) + { + aTimeBuffer.actime=pLastAccessTime->Seconds; + } + else + { + aTimeBuffer.actime=aFileStat.st_atime; + } + + if ( pLastWriteTime != 0 ) + { + aTimeBuffer.modtime=pLastWriteTime->Seconds; + } + else + { + aTimeBuffer.modtime=aFileStat.st_mtime; + } + + /* mfe: Creation time not used here! */ + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"File Times are (in localtime):\n"); + pTM=localtime(&aFileStat.st_ctime); + fprintf(stderr,"CreationTime now '%s'\n",asctime(pTM)); + pTM=localtime(&aTimeBuffer.actime); + fprintf(stderr,"AccessTime now '%s'\n",asctime(pTM)); + pTM=localtime(&aTimeBuffer.modtime); + fprintf(stderr,"Modification now '%s'\n",asctime(pTM)); + + fprintf(stderr,"File Times are (in UTC):\n"); + fprintf(stderr,"CreationTime now '%s'\n",ctime(&aFileStat.st_ctime)); + fprintf(stderr,"AccessTime now '%s'\n",ctime(&aTimeBuffer.actime)); + fprintf(stderr,"Modification now '%s'\n",ctime(&aTimeBuffer.modtime)); +#endif + + nRet=utime(pszFilePath,&aTimeBuffer); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +oslFileError SAL_CALL osl_setFileTime ( + rtl_uString* ustrFileURL, + const TimeValue* pCreationTime, + const TimeValue* pLastAccessTime, + const TimeValue* pLastWriteTime ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrFileURL ); + + /* convert file url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrFileURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_setFileTime( path, pCreationTime, pLastAccessTime, pLastWriteTime ); +} diff --git a/sal/osl/unx/file_url.cxx b/sal/osl/unx/file_url.cxx new file mode 100644 index 000000000000..26290957f802 --- /dev/null +++ b/sal/osl/unx/file_url.cxx @@ -0,0 +1,962 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "file_url.h" + +#include "system.h" + +#include <limits.h> +#include <errno.h> +#include <strings.h> +#include <unistd.h> + +#include "osl/file.hxx" +#include <osl/security.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/process.h> + +#include <rtl/uri.h> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.h> +#include "rtl/textcvt.h" + +#include "file_error_transl.h" +#include "file_path_helper.hxx" + +#include "uunxapi.hxx" + +/*************************************************** + + General note + + This file contains the part that handles File URLs. + + File URLs as scheme specific notion of URIs + (RFC2396) may be handled platform independend, but + will not in osl which is considered wrong. + Future version of osl should handle File URLs this + way. In rtl/uri there is already an URI parser etc. + so this code should be consolidated. + + **************************************************/ +/************************************************************************ + * ToDo + * + * Fix osl_getCanonicalName + * + ***********************************************************************/ + + +/*************************************************** + * namespace directives + **************************************************/ + +using namespace osl; + +/*************************************************** + * constants + **************************************************/ + +const sal_Unicode UNICHAR_SLASH = ((sal_Unicode)'/'); +const sal_Unicode UNICHAR_COLON = ((sal_Unicode)':'); +const sal_Unicode UNICHAR_DOT = ((sal_Unicode)'.'); + +/****************************************************************************** + * + * Exported Module Functions + * + *****************************************************************************/ + +/* a slightly modified version of Pchar in rtl/source/uri.c */ +const sal_Bool uriCharClass[128] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /* pqrstuvwxyz{|}~ */ +}; + + +/* check for top wrong usage strings */ +/* +static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len ) +{ + rtl_uString *pTmp = NULL; + sal_Bool bRet; + + rtl_uString_newFromStr_WithLength( &pTmp, path, len ); + + rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length ); + + bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) ); + + rtl_uString_release( pTmp ); + return bRet; +} +*/ + +/****************************************************************************/ +/* osl_getCanonicalName */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uString** pustrValidURL ) +{ + OSL_ENSURE(0, "osl_getCanonicalName not implemented"); + + rtl_uString_newFromString(pustrValidURL, ustrFileURL); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_getSystemPathFromFileURL */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath ) +{ + sal_Int32 nIndex; + rtl_uString * pTmp = NULL; + + sal_Unicode encodedSlash[3] = { '%', '2', 'F' }; + sal_Unicode protocolDelimiter[3] = { ':', '/', '/' }; + + /* temporary hack: if already system path, return ustrFileURL */ + /* + if( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) + { + OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" ); + rtl_uString_assign( pustrSystemPath, ustrFileURL ); + return osl_File_E_None; + } + */ + + /* a valid file url may not start with '/' */ + if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) ) + { + return osl_File_E_INVAL; + } + + /* Check for non file:// protocols */ + + nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 ); + if ( -1 != nIndex && (4 != nIndex || 0 != rtl_ustr_ascii_shortenedCompare_WithLength( ustrFileURL->buffer, ustrFileURL->length,"file", 4 ) ) ) + { + return osl_File_E_INVAL; + } + + /* search for encoded slashes (%2F) and decode every single token if we find one */ + + nIndex = 0; + + if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) ) + { + rtl_uString * ustrPathToken = NULL; + sal_Int32 nOffset = 7; + + do + { + nOffset += nIndex; + + /* break url down in '/' devided tokens tokens */ + nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' ); + + /* copy token to new string */ + rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset, + -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ ); + + /* decode token */ + rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); + + /* the result should not contain any '/' */ + if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) ) + { + rtl_uString_release( pTmp ); + rtl_uString_release( ustrPathToken ); + + return osl_File_E_INVAL; + } + + } while( -1 != nIndex ); + + /* release temporary string and restore index variable */ + rtl_uString_release( ustrPathToken ); + nIndex = 0; + } + + /* protocol and server should not be encoded, so decode the whole string */ + rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); + + /* check if file protocol specified */ + /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ + if( 7 <= pTmp->length ) + { + rtl_uString * pProtocol = NULL; + rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 ); + + /* protocol is case insensitive */ + rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length ); + + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) ) + nIndex = 7; + + rtl_uString_release( pProtocol ); + } + + /* skip "localhost" or "127.0.0.1" if "file://" is specified */ + /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ + if( nIndex && ( 10 <= pTmp->length - nIndex ) ) + { + rtl_uString * pServer = NULL; + rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 ); + + /* server is case insensitive */ + rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length ); + + if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) || + ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) ) + { + /* don't exclude the '/' */ + nIndex += 9; + } + + rtl_uString_release( pServer ); + } + + if( nIndex ) + rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex ); + + /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ + if( (sal_Unicode) '~' == pTmp->buffer[0] ) + { + /* check if another user is specified */ + if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) ) + { + rtl_uString *pTmp2 = NULL; + + /* osl_getHomeDir returns file URL */ + osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 ); + + /* remove "file://" prefix */ + rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 ); + + /* replace '~' in original string */ + rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 ); + rtl_uString_release( pTmp2 ); + } + + else + { + /* FIXME: replace ~user with users home directory */ + return osl_File_E_INVAL; + } + } + + /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ + /* + OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); + */ + + *pustrSystemPath = pTmp; + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_getFileURLFromSystemPath */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL ) +{ + static const sal_Unicode pDoubleSlash[2] = { '/', '/' }; + + rtl_uString *pTmp = NULL; + sal_Int32 nIndex; + + if( 0 == ustrSystemPath->length ) + return osl_File_E_INVAL; + + /* temporary hack: if already file url, return ustrSystemPath */ + + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) ) + { + /* + if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) ) + { + OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" ); + rtl_uString_assign( pustrFileURL, ustrSystemPath ); + } + else + { + rtl_uString *pTmp2 = NULL; + + OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" ); + rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 ); + rtl_uString_newFromAscii( &pTmp2, "file://" ); + rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 ); + rtl_uString_release( pTmp2 ); + } + return osl_File_E_None; + */ + return osl_File_E_INVAL; + } + + + /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ + if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] ) + { + /* check if another user is specified */ + if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) ) + { + /* osl_getHomeDir returns file URL */ + osl_getHomeDir( osl_getCurrentSecurity(), &pTmp ); + + /* remove "file://" prefix */ + rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 ); + + /* replace '~' in original string */ + rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp ); + } + + else + { + /* FIXME: replace ~user with users home directory */ + return osl_File_E_INVAL; + } + } + + /* check if initial string contains double instances of '/' */ + nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 ); + if( -1 != nIndex ) + { + sal_Int32 nSrcIndex; + sal_Int32 nDeleted = 0; + + /* if pTmp is not already allocated, copy ustrSystemPath for modification */ + if( NULL == pTmp ) + rtl_uString_newFromString( &pTmp, ustrSystemPath ); + + /* adapt index to pTmp */ + nIndex += pTmp->length - ustrSystemPath->length; + + /* remove all occurances of '//' */ + for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ ) + { + if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) ) + nDeleted++; + else + pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex]; + } + + /* adjust length member */ + pTmp->length -= nDeleted; + } + + if( NULL == pTmp ) + rtl_uString_assign( &pTmp, ustrSystemPath ); + + /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ + /* + OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); + */ + + /* file URLs must be URI encoded */ + rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL ); + + rtl_uString_release( pTmp ); + + /* absolute urls should start with 'file://' */ + if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] ) + { + rtl_uString *pProtocol = NULL; + + rtl_uString_newFromAscii( &pProtocol, "file://" ); + rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL ); + rtl_uString_release( pProtocol ); + } + + return osl_File_E_None; +} + +/**************************************************************************** + * osl_getSystemPathFromFileURL_Ex - helper function + * clients may specify if they want to accept relative + * URLs or not + ****************************************************************************/ + +oslFileError osl_getSystemPathFromFileURL_Ex( + rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative) +{ + rtl_uString* temp = 0; + oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp); + + if (osl_File_E_None == osl_error) + { + if (bAllowRelative || (UNICHAR_SLASH == temp->buffer[0])) + { + *pustrSystemPath = temp; + } + else + { + rtl_uString_release(temp); + osl_error = osl_File_E_INVAL; + } + } + + return osl_error; +} + +namespace /* private */ +{ + + /****************************************************** + * Helper function, return a pinter to the final '\0' + * of a string + ******************************************************/ + + sal_Unicode* ustrtoend(sal_Unicode* pStr) + { + return (pStr + rtl_ustr_getLength(pStr)); + } + + /********************************************* + + ********************************************/ + + sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d) + { + sal_Unicode* p = ustrtoend(d); + *p++ = chr; + *p = 0; + return d; + } + + /****************************************************** + * + ******************************************************/ + + bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr) + { + sal_Unicode* p = ustrtoend(pStr); + if (p > pStr) + p--; + return (*p == Chr); + } + + /****************************************************** + * Remove the last part of a path, a path that has + * only a '/' or no '/' at all will be returned + * unmodified + ******************************************************/ + + sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath) + { + /* we always may skip -2 because we + may at least stand on a '/' but + either there is no other character + before this '/' or it's another + character than the '/' + */ + sal_Unicode* p = ustrtoend(aPath) - 2; + + // move back to the next path separator + // or to the start of the string + while ((p > aPath) && (*p != UNICHAR_SLASH)) + p--; + + if (p >= aPath) + { + if (UNICHAR_SLASH == *p) + { + p++; + *p = '\0'; + } + else + { + *p = '\0'; + } + } + + return aPath; + } + + /****************************************************** + * + ******************************************************/ + + oslFileError _osl_resolvepath( + /*inout*/ sal_Unicode* path, + /*inout*/ sal_Unicode* current_pos, + /*inout*/ bool* failed) + { + oslFileError ferr = osl_File_E_None; + + if (!*failed) + { + char unresolved_path[PATH_MAX]; + if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path))) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + char resolved_path[PATH_MAX]; + if (realpath(unresolved_path, resolved_path)) + { + if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX)) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + current_pos = ustrtoend(path) - 1; + } + else + { + if (EACCES == errno || ENOTDIR == errno || ENOENT == errno) + *failed = true; + else + ferr = oslTranslateFileError(OSL_FET_ERROR, errno); + } + } + + return ferr; + } + + /****************************************************** + * Works even with non existing paths. The resulting + * path must not exceed PATH_MAX else + * osl_File_E_NAMETOOLONG is the result + ******************************************************/ + + oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path) + { + // the given unresolved path must not exceed PATH_MAX + if (unresolved_path.getLength() >= (PATH_MAX - 2)) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + sal_Unicode path_resolved_so_far[PATH_MAX]; + const sal_Unicode* punresolved = unresolved_path.getStr(); + sal_Unicode* presolvedsf = path_resolved_so_far; + + // reserve space for leading '/' and trailing '\0' + // do not exceed this limit + sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2; + + // if realpath fails with error ENOTDIR, EACCES or ENOENT + // we will not call it again, because _osl_realpath should also + // work with non existing directories etc. + bool realpath_failed = false; + oslFileError ferr; + + path_resolved_so_far[0] = '\0'; + + while (*punresolved != '\0') + { + // ignore '/.' , skip one part back when '/..' + + if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf)) + { + if ('\0' == *(punresolved + 1)) + { + punresolved++; + continue; + } + else if (UNICHAR_SLASH == *(punresolved + 1)) + { + punresolved += 2; + continue; + } + else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2)))) + { + _rmlastpathtoken(path_resolved_so_far); + + presolvedsf = ustrtoend(path_resolved_so_far) - 1; + + if (UNICHAR_SLASH == *(punresolved + 2)) + punresolved += 3; + else + punresolved += 2; + + continue; + } + else // a file or directory name may start with '.' + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if ('\0' == *punresolved && !realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + } + } + } + else if (UNICHAR_SLASH == *punresolved) + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if (!realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + + if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH)) + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(UNICHAR_SLASH, path_resolved_so_far); + } + } + } + else // any other character + { + if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) + return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); + + ustrchrcat(*punresolved++, path_resolved_so_far); + + if ('\0' == *punresolved && !realpath_failed) + { + ferr = _osl_resolvepath( + path_resolved_so_far, + presolvedsf, + &realpath_failed); + + if (osl_File_E_None != ferr) + return ferr; + } + } + } + + sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far); + + OSL_ASSERT(len < PATH_MAX); + + resolved_path = rtl::OUString(path_resolved_so_far, len); + + return osl_File_E_None; + } + +} // end namespace private + + +/****************************************************** + * osl_getAbsoluteFileURL + ******************************************************/ + +oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL) +{ + FileBase::RC rc; + rtl::OUString unresolved_path; + + rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path); + + if(FileBase::E_None != rc) + return oslFileError(rc); + + if (systemPathIsRelativePath(unresolved_path)) + { + rtl::OUString base_path; + rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False); + + if (FileBase::E_None != rc) + return oslFileError(rc); + + rtl::OUString abs_path; + systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path); + + unresolved_path = abs_path; + } + + rtl::OUString resolved_path; + rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path); + + if (FileBase::E_None == rc) + { + rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL); + OSL_ASSERT(FileBase::E_None == rc); + } + + return oslFileError(rc); +} + + +namespace /* private */ +{ + + /********************************************* + No separate error code if unicode to text + conversion or getenv fails because for the + caller there is no difference why a file + could not be found in $PATH + ********************************************/ + + bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result) + { + bool bfound = false; + rtl::OUString path = rtl::OUString::createFromAscii("PATH"); + rtl::OUString env_path; + + if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData)) + bfound = osl::searchPath(file_path, env_path, result); + + return bfound; + } + + /********************************************* + No separate error code if unicode to text + conversion or getcwd fails because for the + caller there is no difference why a file + could not be found in CDW + ********************************************/ + + bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result) + { + bool bfound = false; + rtl::OUString cwd_url; + + if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData)) + { + rtl::OUString cwd; + FileBase::getSystemPathFromFileURL(cwd_url, cwd); + bfound = osl::searchPath(file_path, cwd, result); + } + return bfound; + } + + /********************************************* + + ********************************************/ + + bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result) + { + return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result)); + } + +} // end namespace private + + +/**************************************************************************** + * osl_searchFileURL + ***************************************************************************/ + +oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL) +{ + OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter"); + + FileBase::RC rc; + rtl::OUString file_path; + + // try to interpret search path as file url else assume it's a system path list + rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path); + if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc)) + file_path = ustrFilePath; + else if (FileBase::E_None != rc) + return oslFileError(rc); + + bool bfound = false; + rtl::OUString result; + + if (find_in_searchPath(file_path, ustrSearchPath, result) || + find_in_PATH(file_path, result) || + find_in_CWD(file_path, result)) + { + rtl::OUString resolved; + + if (osl::realpath(result, resolved)) + { +#if OSL_DEBUG_LEVEL > 0 + oslFileError osl_error = +#endif + osl_getFileURLFromSystemPath(resolved.pData, pustrURL); + OSL_ASSERT(osl_File_E_None == osl_error); + bfound = true; + } + } + return bfound ? osl_File_E_None : osl_File_E_NOENT; +} + + +/**************************************************************************** + * FileURLToPath + ***************************************************************************/ + +oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath); + + if(osl_File_E_None != osl_error) + return osl_error; + + osl_systemPathRemoveSeparator(ustrSystemPath); + + /* convert unicode path to text */ + if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length)) + osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); + + rtl_uString_release(ustrSystemPath); + + return osl_error; +} + +/***************************************************************************** + * UnicodeToText + ****************************************************************************/ + +namespace /* private */ +{ + class UnicodeToTextConverter_Impl + { + rtl_UnicodeToTextConverter m_converter; + + UnicodeToTextConverter_Impl() + : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding())) + {} + + ~UnicodeToTextConverter_Impl() + { + rtl_destroyUnicodeToTextConverter (m_converter); + } + public: + static UnicodeToTextConverter_Impl & getInstance() + { + static UnicodeToTextConverter_Impl g_theConverter; + return g_theConverter; + } + + sal_Size convert( + sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes, + sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars) + { + OSL_ASSERT(m_converter != 0); + return rtl_convertUnicodeToText ( + m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars); + } + }; +} // end namespace private + +int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen ) +{ + sal_uInt32 nInfo = 0; + sal_Size nSrcChars = 0; + + sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert ( + uniText, uniTextLen, buffer, bufLen, + OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars); + + if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL ) + { + errno = EOVERFLOW; + return 0; + } + + /* ensure trailing '\0' */ + buffer[nDestBytes] = '\0'; + return nDestBytes; +} + +/***************************************************************************** + * TextToUnicode + ****************************************************************************/ + +namespace /* private */ +{ + class TextToUnicodeConverter_Impl + { + rtl_TextToUnicodeConverter m_converter; + + TextToUnicodeConverter_Impl() + : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding())) + {} + + ~TextToUnicodeConverter_Impl() + { + rtl_destroyTextToUnicodeConverter (m_converter); + } + + public: + static TextToUnicodeConverter_Impl & getInstance() + { + static TextToUnicodeConverter_Impl g_theConverter; + return g_theConverter; + } + + sal_Size convert( + sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars, + sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes) + { + OSL_ASSERT(m_converter != 0); + return rtl_convertTextToUnicode ( + m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes); + } + }; +} // end namespace private + +int TextToUnicode( + const char* text, + size_t text_buffer_size, + sal_Unicode* unic_text, + sal_Int32 unic_text_buffer_size) +{ + sal_uInt32 nInfo = 0; + sal_Size nSrcChars = 0; + + sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert( + text, text_buffer_size, unic_text, unic_text_buffer_size, + OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars); + + if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL) + { + errno = EOVERFLOW; + return 0; + } + + /* ensure trailing '\0' */ + unic_text[nDestBytes] = '\0'; + return nDestBytes; +} diff --git a/sal/osl/unx/file_url.h b/sal/osl/unx/file_url.h new file mode 100644 index 000000000000..0a0d07823bba --- /dev/null +++ b/sal/osl/unx/file_url.h @@ -0,0 +1,69 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_FILE_URL_H +#define INCLUDED_FILE_URL_H + +#include "osl/file.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************** + * osl_getSystemPathFromFileURL_Ex + *************************************************/ + +#define FURL_ALLOW_RELATIVE sal_True +#define FURL_DENY_RELATIVE sal_False + +oslFileError osl_getSystemPathFromFileURL_Ex(rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative); + +/************************************************** + * FileURLToPath + *************************************************/ + +oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL); + +/*************************************************** + * UnicodeToText + **************************************************/ + +int UnicodeToText(char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen); + +/*************************************************** + * TextToUniCode + **************************************************/ + +int TextToUnicode(const char* text, size_t text_buffer_size, sal_Unicode* unic_text, sal_Int32 unic_text_buffer_size); + +#ifdef __cplusplus +} +#endif + +#endif /* #define INCLUDED_FILE_URL_H */ diff --git a/sal/osl/unx/file_volume.cxx b/sal/osl/unx/file_volume.cxx new file mode 100644 index 000000000000..cc7f61ec6a8b --- /dev/null +++ b/sal/osl/unx/file_volume.cxx @@ -0,0 +1,1155 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/file.h" + +#include "osl/diagnose.h" +#include "osl/thread.h" +#include "rtl/alloc.h" + +#include "file_error_transl.h" +#include "file_url.h" +#include "system.h" + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> + +#ifdef HAVE_STATFS_H +#undef HAVE_STATFS_H +#endif + +#if defined(LINUX) && defined(__FreeBSD_kernel__) +#undef LINUX +#define FREEBSD 1 +#endif + + +#if defined(SOLARIS) + +#include <sys/mnttab.h> +#include <sys/statvfs.h> +#define HAVE_STATFS_H +#include <sys/fs/ufs_quota.h> +static const sal_Char* MOUNTTAB="/etc/mnttab"; + +#elif defined(LINUX) + +#include <mntent.h> +#include <sys/vfs.h> +#define HAVE_STATFS_H +#include <sys/quota.h> +//#include <ctype.h> +static const sal_Char* MOUNTTAB="/etc/mtab"; + +#elif defined(NETBSD) || defined(FREEBSD) + +#include <sys/param.h> +#include <sys/ucred.h> +#include <sys/mount.h> +#include <ufs/ufs/quota.h> +//#include <ctype.h> +#define HAVE_STATFS_H + +/* No mounting table on *BSD + * This information is stored only in the kernel. */ +/* static const sal_Char* MOUNTTAB="/etc/mtab"; */ + +#elif defined(MACOSX) + +#include <ufs/ufs/quota.h> +//#include <ctype.h> +#include <sys/param.h> +#include <sys/mount.h> +#define HAVE_STATFS_H +// static const sal_Char* MOUNTTAB="/etc/mtab"; + +#endif /* HAVE_STATFS_H */ + +/************************************************************************ + * ToDo + * + * - Fix: check for corresponding struct sizes in exported functions + * - check size/use of oslVolumeDeviceHandle + * - check size/use of oslVolumeInfo + ***********************************************************************/ +/****************************************************************************** + * + * Data Type Definition + * + ******************************************************************************/ + +typedef struct _oslVolumeDeviceHandleImpl +{ + sal_Char pszMountPoint[PATH_MAX]; + sal_Char pszFilePath[PATH_MAX]; + sal_Char pszDevice[PATH_MAX]; + sal_Char ident[4]; + sal_uInt32 RefCount; +} oslVolumeDeviceHandleImpl; + +/****************************************************************************** + * + * 'removeable device' aka floppy functions + * + *****************************************************************************/ + +static oslVolumeDeviceHandle osl_isFloppyDrive(const sal_Char* pszPath); +static oslFileError osl_mountFloppy(oslVolumeDeviceHandle hFloppy); +static oslFileError osl_unmountFloppy(oslVolumeDeviceHandle hFloppy); + +#if defined(SOLARIS) +static sal_Bool osl_isFloppyMounted(sal_Char* pszPath, sal_Char* pszMountPath); +static sal_Bool osl_getFloppyMountEntry(const sal_Char* pszPath, sal_Char* pBuffer); +static sal_Bool osl_checkFloppyPath(sal_Char* pszPath, sal_Char* pszFilePath, sal_Char* pszDevicePath); +#endif /* SOLARIS */ + +#if defined(LINUX) +static sal_Bool osl_isFloppyMounted(oslVolumeDeviceHandleImpl* pDevice); +static sal_Bool osl_getFloppyMountEntry(const sal_Char* pszPath, oslVolumeDeviceHandleImpl* pItem); +#endif /* LINUX */ + +#ifdef DEBUG_OSL_FILE +static void osl_printFloppyHandle(oslVolumeDeviceHandleImpl* hFloppy); +#endif /* DEBUG_OSL_FILE */ + +/****************************************************************************** + * + * C-String Function Declarations + * + *****************************************************************************/ + +static oslFileError osl_psz_getVolumeInformation(const sal_Char* , oslVolumeInfo* pInfo, sal_uInt32 uFieldMask); + +/****************************************************************************/ +/* osl_getVolumeInformation */ +/****************************************************************************/ + +oslFileError osl_getVolumeInformation( rtl_uString* ustrDirectoryURL, oslVolumeInfo* pInfo, sal_uInt32 uFieldMask ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrDirectoryURL ); + OSL_ASSERT( pInfo ); + + /* convert directory url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_getVolumeInformation( path, pInfo, uFieldMask); +} + +/****************************************************************************** + * + * C-String Versions of Exported Module Functions + * + *****************************************************************************/ + +#ifdef HAVE_STATFS_H + +#if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) +# define __OSL_STATFS_STRUCT struct statfs +# define __OSL_STATFS(dir, sfs) statfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_bsize)) +# define __OSL_STATFS_TYPENAME(a) ((a).f_fstypename) +# define __OSL_STATFS_ISREMOTE(a) (((a).f_type & MNT_LOCAL) == 0) + +/* always return true if queried for the properties of + the file system. If you think this is wrong under any + of the target platforms fix it!!!! */ +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* FREEBSD || NETBSD || MACOSX */ + +#if defined(LINUX) +# define __OSL_NFS_SUPER_MAGIC 0x6969 +# define __OSL_SMB_SUPER_MAGIC 0x517B +# define __OSL_MSDOS_SUPER_MAGIC 0x4d44 +# define __OSL_NTFS_SUPER_MAGIC 0x5346544e +# define __OSL_STATFS_STRUCT struct statfs +# define __OSL_STATFS(dir, sfs) statfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_bsize)) +# define __OSL_STATFS_IS_NFS(a) (__OSL_NFS_SUPER_MAGIC == (a).f_type) +# define __OSL_STATFS_IS_SMB(a) (__OSL_SMB_SUPER_MAGIC == (a).f_type) +# define __OSL_STATFS_ISREMOTE(a) (__OSL_STATFS_IS_NFS((a)) || __OSL_STATFS_IS_SMB((a))) +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) ((__OSL_MSDOS_SUPER_MAGIC != (a).f_type) && (__OSL_NTFS_SUPER_MAGIC != (a).f_type)) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) ((__OSL_MSDOS_SUPER_MAGIC != (a).f_type)) +#endif /* LINUX */ + +#if defined(SOLARIS) +# define __OSL_STATFS_STRUCT struct statvfs +# define __OSL_STATFS(dir, sfs) statvfs((dir), (sfs)) +# define __OSL_STATFS_BLKSIZ(a) ((sal_uInt64)((a).f_frsize)) +# define __OSL_STATFS_TYPENAME(a) ((a).f_basetype) +# define __OSL_STATFS_ISREMOTE(a) (rtl_str_compare((a).f_basetype, "nfs") == 0) + +/* always return true if queried for the properties of + the file system. If you think this is wrong under any + of the target platforms fix it!!!! */ +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* SOLARIS */ + +# define __OSL_STATFS_INIT(a) (memset(&(a), 0, sizeof(__OSL_STATFS_STRUCT))) + +#else /* no statfs available */ + +# define __OSL_STATFS_STRUCT struct dummy {int i;} +# define __OSL_STATFS_INIT(a) ((void)0) +# define __OSL_STATFS(dir, sfs) (1) +# define __OSL_STATFS_ISREMOTE(sfs) (0) +# define __OSL_STATFS_IS_CASE_SENSITIVE_FS(a) (1) +# define __OSL_STATFS_IS_CASE_PRESERVING_FS(a) (1) +#endif /* HAVE_STATFS_H */ + + +static oslFileError osl_psz_getVolumeInformation ( + const sal_Char* pszDirectory, oslVolumeInfo* pInfo, sal_uInt32 uFieldMask) +{ + __OSL_STATFS_STRUCT sfs; + + if (!pInfo) + return osl_File_E_INVAL; + + __OSL_STATFS_INIT(sfs); + + pInfo->uValidFields = 0; + pInfo->uAttributes = 0; + + if ((__OSL_STATFS(pszDirectory, &sfs)) < 0) + { + oslFileError result = oslTranslateFileError(OSL_FET_ERROR, errno); + return (result); + } + + /* FIXME: how to detect the kind of storage (fixed, cdrom, ...) */ + if (uFieldMask & osl_VolumeInfo_Mask_Attributes) + { + if (__OSL_STATFS_ISREMOTE(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Remote; + + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + + if (uFieldMask & osl_VolumeInfo_Mask_FileSystemCaseHandling) + { + if (__OSL_STATFS_IS_CASE_SENSITIVE_FS(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Case_Sensitive; + + if (__OSL_STATFS_IS_CASE_PRESERVING_FS(sfs)) + pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved; + + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + + pInfo->uTotalSpace = 0; + pInfo->uFreeSpace = 0; + pInfo->uUsedSpace = 0; + +#if defined(__OSL_STATFS_BLKSIZ) + + if ((uFieldMask & osl_VolumeInfo_Mask_TotalSpace) || + (uFieldMask & osl_VolumeInfo_Mask_UsedSpace)) + { + pInfo->uTotalSpace = __OSL_STATFS_BLKSIZ(sfs); + pInfo->uTotalSpace *= (sal_uInt64)(sfs.f_blocks); + pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace; + } + + if ((uFieldMask & osl_VolumeInfo_Mask_FreeSpace) || + (uFieldMask & osl_VolumeInfo_Mask_UsedSpace)) + { + pInfo->uFreeSpace = __OSL_STATFS_BLKSIZ(sfs); + + if (getuid() == 0) + pInfo->uFreeSpace *= (sal_uInt64)(sfs.f_bfree); + else + pInfo->uFreeSpace *= (sal_uInt64)(sfs.f_bavail); + + pInfo->uValidFields |= osl_VolumeInfo_Mask_FreeSpace; + } + +#endif /* __OSL_STATFS_BLKSIZ */ + + if ((pInfo->uValidFields & osl_VolumeInfo_Mask_TotalSpace) && + (pInfo->uValidFields & osl_VolumeInfo_Mask_FreeSpace )) + { + pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace; + pInfo->uValidFields |= osl_VolumeInfo_Mask_UsedSpace; + } + + pInfo->uMaxNameLength = 0; + if (uFieldMask & osl_VolumeInfo_Mask_MaxNameLength) + { + long nLen = pathconf(pszDirectory, _PC_NAME_MAX); + if (nLen > 0) + { + pInfo->uMaxNameLength = (sal_uInt32)nLen; + pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength; + } + } + + pInfo->uMaxPathLength = 0; + if (uFieldMask & osl_VolumeInfo_Mask_MaxPathLength) + { + long nLen = pathconf (pszDirectory, _PC_PATH_MAX); + if (nLen > 0) + { + pInfo->uMaxPathLength = (sal_uInt32)nLen; + pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength; + } + } + +#if defined(__OSL_STATFS_TYPENAME) + + if (uFieldMask & osl_VolumeInfo_Mask_FileSystemName) + { + rtl_string2UString( + &(pInfo->ustrFileSystemName), + __OSL_STATFS_TYPENAME(sfs), + rtl_str_getLength(__OSL_STATFS_TYPENAME(sfs)), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS); + OSL_ASSERT(pInfo->ustrFileSystemName != 0); + + pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName; + } + +#endif /* __OSL_STATFS_TYPENAME */ + + if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle) + { + /* FIXME: check also entries in mntent for the device + and fill it with correct values */ + + *pInfo->pDeviceHandle = osl_isFloppyDrive(pszDirectory); + + if (*pInfo->pDeviceHandle) + { + pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle; + pInfo->uAttributes |= osl_Volume_Attribute_Removeable; + pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; + } + } + return osl_File_E_None; +} + +/****************************************************************************** + * + * GENERIC FLOPPY FUNCTIONS + * + *****************************************************************************/ + + +/***************************************** + * osl_unmountVolumeDevice + ****************************************/ + +oslFileError osl_unmountVolumeDevice( oslVolumeDeviceHandle Handle ) +{ + oslFileError tErr = osl_File_E_NOSYS; + + tErr = osl_unmountFloppy(Handle); + + /* Perhaps current working directory is set to mount point */ + + if ( tErr ) + { + sal_Char *pszHomeDir = getenv("HOME"); + + if ( pszHomeDir && strlen( pszHomeDir ) && 0 == chdir( pszHomeDir ) ) + { + /* try again */ + + tErr = osl_unmountFloppy(Handle); + + OSL_ENSURE( tErr, "osl_unmountvolumeDevice: CWD was set to volume mount point" ); + } + } + + return tErr; +} + +/***************************************** + * osl_automountVolumeDevice + ****************************************/ + +oslFileError osl_automountVolumeDevice( oslVolumeDeviceHandle Handle ) +{ + oslFileError tErr = osl_File_E_NOSYS; + + tErr = osl_mountFloppy(Handle); + + return tErr; +} + +/***************************************** + * osl_getVolumeDeviceMountPath + ****************************************/ +static rtl_uString* oslMakeUStrFromPsz(const sal_Char* pszStr, rtl_uString** ustrValid) +{ + rtl_string2UString( + ustrValid, + pszStr, + rtl_str_getLength( pszStr ), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*ustrValid != 0); + + return *ustrValid; +} + +oslFileError osl_getVolumeDeviceMountPath( oslVolumeDeviceHandle Handle, rtl_uString **pstrPath ) +{ + oslVolumeDeviceHandleImpl* pItem = (oslVolumeDeviceHandleImpl*) Handle; + sal_Char Buffer[PATH_MAX]; + + Buffer[0] = '\0'; + + if ( pItem == 0 || pstrPath == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"Handle is:\n"); + osl_printFloppyHandle(pItem); +#endif + + snprintf(Buffer, sizeof(Buffer), "file://%s", pItem->pszMountPoint); + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"Mount Point is: '%s'\n",Buffer); +#endif + + oslMakeUStrFromPsz(Buffer, pstrPath); + + return osl_File_E_None; +} + +/***************************************** + * osl_acquireVolumeDeviceHandle + ****************************************/ + +oslFileError SAL_CALL osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle ) +{ + oslVolumeDeviceHandleImpl* pItem =(oslVolumeDeviceHandleImpl*) Handle; + + if ( pItem == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + + ++pItem->RefCount; + + return osl_File_E_None; +} + +/***************************************** + * osl_releaseVolumeDeviceHandle + ****************************************/ + +oslFileError osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle ) +{ + oslVolumeDeviceHandleImpl* pItem =(oslVolumeDeviceHandleImpl*) Handle; + + if ( pItem == 0 ) + { + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { + return osl_File_E_INVAL; + } + + --pItem->RefCount; + + if ( pItem->RefCount == 0 ) + { + rtl_freeMemory(pItem); + } + + return osl_File_E_None; +} + +#ifndef MACOSX + +/***************************************** + * osl_newVolumeDeviceHandleImpl + ****************************************/ + +static oslVolumeDeviceHandleImpl* osl_newVolumeDeviceHandleImpl() +{ + oslVolumeDeviceHandleImpl* pHandle; + const size_t nSizeOfHandle = sizeof(oslVolumeDeviceHandleImpl); + + pHandle = (oslVolumeDeviceHandleImpl*) rtl_allocateMemory (nSizeOfHandle); + if (pHandle != NULL) + { + pHandle->ident[0] = 'O'; + pHandle->ident[1] = 'V'; + pHandle->ident[2] = 'D'; + pHandle->ident[3] = 'H'; + pHandle->pszMountPoint[0] = '\0'; + pHandle->pszFilePath[0] = '\0'; + pHandle->pszDevice[0] = '\0'; + pHandle->RefCount = 1; + } + return pHandle; +} + +/***************************************** + * osl_freeVolumeDeviceHandleImpl + ****************************************/ + +static void osl_freeVolumeDeviceHandleImpl (oslVolumeDeviceHandleImpl* pHandle) +{ + if (pHandle != NULL) + rtl_freeMemory (pHandle); +} +#endif + +/****************************************************************************** + * + * SOLARIS FLOPPY FUNCTIONS + * + *****************************************************************************/ + +#if defined(SOLARIS) +/* compare a given devicename with the typical device names on a Solaris box */ +static sal_Bool +osl_isAFloppyDevice (const char* pDeviceName) +{ + const char* pFloppyDevice [] = { + "/dev/fd", "/dev/rfd", + "/dev/diskette", "/dev/rdiskette", + "/vol/dev/diskette", "/vol/dev/rdiskette" + }; + + int i; + for (i = 0; i < (sizeof(pFloppyDevice)/sizeof(pFloppyDevice[0])); i++) + { + if (strncmp(pDeviceName, pFloppyDevice[i], strlen(pFloppyDevice[i])) == 0) + return sal_True; + } + return sal_False; +} + +/* compare two directories whether the first may be a parent of the second. this + * does not realpath() resolving */ +static sal_Bool +osl_isAParentDirectory (const char* pParentDir, const char* pSubDir) +{ + return strncmp(pParentDir, pSubDir, strlen(pParentDir)) == 0; +} + +/* the name of the routine is obviously silly. But anyway create a + * oslVolumeDeviceHandle with correct mount point, device name and a resolved filepath + * only if pszPath points to file or directory on a floppy */ +static oslVolumeDeviceHandle +osl_isFloppyDrive(const sal_Char* pszPath) +{ + FILE* pMountTab; + struct mnttab aMountEnt; + oslVolumeDeviceHandleImpl* pHandle; + + if ((pHandle = osl_newVolumeDeviceHandleImpl()) == NULL) + { + return NULL; + } + if (realpath(pszPath, pHandle->pszFilePath) == NULL) + { + osl_freeVolumeDeviceHandleImpl (pHandle); + return NULL; + } + if ((pMountTab = fopen (MOUNTTAB, "r")) == NULL) + { + osl_freeVolumeDeviceHandleImpl (pHandle); + return NULL; + } + + while (getmntent(pMountTab, &aMountEnt) == 0) + { + const char *pMountPoint = aMountEnt.mnt_mountp; + const char *pDevice = aMountEnt.mnt_special; + if ( osl_isAParentDirectory (aMountEnt.mnt_mountp, pHandle->pszFilePath) + && osl_isAFloppyDevice (aMountEnt.mnt_special)) + { + /* skip the last item for it is the name of the disk */ + char * pc = strrchr( aMountEnt.mnt_special, '/' ); + + if ( NULL != pc ) + { + int len = pc - aMountEnt.mnt_special; + + strncpy( pHandle->pszDevice, aMountEnt.mnt_special, len ); + pHandle->pszDevice[len] = '\0'; + } + else + { + /* #106048 use save str functions to avoid buffer overflows */ + memset(pHandle->pszDevice, 0, sizeof(pHandle->pszDevice)); + strncpy(pHandle->pszDevice, aMountEnt.mnt_special, sizeof(pHandle->pszDevice) - 1); + } + + /* remember the mount point */ + memset(pHandle->pszMountPoint, 0, sizeof(pHandle->pszMountPoint)); + strncpy(pHandle->pszMountPoint, aMountEnt.mnt_mountp, sizeof(pHandle->pszMountPoint) - 1); + + fclose (pMountTab); + return pHandle; + } + } + + fclose (pMountTab); + osl_freeVolumeDeviceHandleImpl (pHandle); + return NULL; +} + +static oslFileError osl_mountFloppy(oslVolumeDeviceHandle hFloppy) +{ + FILE* pMountTab; + struct mnttab aMountEnt; + oslVolumeDeviceHandleImpl* pHandle = (oslVolumeDeviceHandleImpl*) hFloppy; + + int nRet=0; + sal_Char pszCmd[512] = ""; + + if ( pHandle == 0 ) + return osl_File_E_INVAL; + + /* FIXME: don't know what this is good for */ + if ( pHandle->ident[0] != 'O' || pHandle->ident[1] != 'V' || pHandle->ident[2] != 'D' || pHandle->ident[3] != 'H' ) + return osl_File_E_INVAL; + + snprintf(pszCmd, sizeof(pszCmd), "eject -q %s > /dev/null 2>&1", pHandle->pszDevice); + + nRet = system( pszCmd ); + + switch ( WEXITSTATUS(nRet) ) + { + case 0: + { + /* lookup the device in mount tab again */ + if ((pMountTab = fopen (MOUNTTAB, "r")) == NULL) + return osl_File_E_BUSY; + + while (getmntent(pMountTab, &aMountEnt) == 0) + { + const char *pMountPoint = aMountEnt.mnt_mountp; + const char *pDevice = aMountEnt.mnt_special; + if ( 0 == strncmp( pHandle->pszDevice, aMountEnt.mnt_special, strlen(pHandle->pszDevice) ) ) + { + memset(pHandle->pszMountPoint, 0, sizeof(pHandle->pszMountPoint)); + strncpy (pHandle->pszMountPoint, aMountEnt.mnt_mountp, sizeof(pHandle->pszMountPoint) - 1); + + fclose (pMountTab); + return osl_File_E_None; + } + } + + fclose (pMountTab); + return osl_File_E_BUSY; + } + //break; // break not necessary here, see return statements before + + case 1: + return osl_File_E_BUSY; + + default: + break; + } + + return osl_File_E_BUSY; +} + +static oslFileError osl_unmountFloppy(oslVolumeDeviceHandle hFloppy) +{ +// FILE* pMountTab; +// struct mnttab aMountEnt; + oslVolumeDeviceHandleImpl* pHandle = (oslVolumeDeviceHandleImpl*) hFloppy; + + int nRet=0; + sal_Char pszCmd[512] = ""; + + if ( pHandle == 0 ) + return osl_File_E_INVAL; + + /* FIXME: don't know what this is good for */ + if ( pHandle->ident[0] != 'O' || pHandle->ident[1] != 'V' || pHandle->ident[2] != 'D' || pHandle->ident[3] != 'H' ) + return osl_File_E_INVAL; + + snprintf(pszCmd, sizeof(pszCmd), "eject %s > /dev/null 2>&1", pHandle->pszDevice); + + nRet = system( pszCmd ); + + switch ( WEXITSTATUS(nRet) ) + { + case 0: + { + FILE* pMountTab; + struct mnttab aMountEnt; + + /* lookup if device is still in mount tab */ + if ((pMountTab = fopen (MOUNTTAB, "r")) == NULL) + return osl_File_E_BUSY; + + while (getmntent(pMountTab, &aMountEnt) == 0) + { + const char *pMountPoint = aMountEnt.mnt_mountp; + const char *pDevice = aMountEnt.mnt_special; + if ( 0 == strncmp( pHandle->pszDevice, aMountEnt.mnt_special, strlen(pHandle->pszDevice) ) ) + { + fclose (pMountTab); + return osl_File_E_BUSY; + } + } + + fclose (pMountTab); + pHandle->pszMountPoint[0] = 0; + return osl_File_E_None; + } + + //break; //break not necessary, see return statements before + + case 1: + return osl_File_E_NODEV; + + case 4: + pHandle->pszMountPoint[0] = 0; + return osl_File_E_None; + + default: + break; + } + + return osl_File_E_BUSY; +} + +#endif /* SOLARIS */ + +/****************************************************************************** + * + * LINUX FLOPPY FUNCTIONS + * + *****************************************************************************/ + +#if defined(LINUX) +static oslVolumeDeviceHandle +osl_isFloppyDrive (const sal_Char* pszPath) +{ + oslVolumeDeviceHandleImpl* pItem = osl_newVolumeDeviceHandleImpl(); + if (osl_getFloppyMountEntry(pszPath, pItem)) + return (oslVolumeDeviceHandle) pItem; + + osl_freeVolumeDeviceHandleImpl (pItem); + return 0; +} +#endif /* LINUX */ + +#if defined(LINUX) +static oslFileError osl_mountFloppy(oslVolumeDeviceHandle hFloppy) +{ + sal_Bool bRet = sal_False; + oslVolumeDeviceHandleImpl* pItem=0; + int nRet; + sal_Char pszCmd[PATH_MAX]; + const sal_Char* pszMountProg = "mount"; + sal_Char* pszSuDo = 0; + sal_Char* pszTmp = 0; + + pszCmd[0] = '\0'; + +#ifdef TRACE_OSL_FILE + fprintf(stderr,"In osl_mountFloppy\n"); +#endif + + pItem = (oslVolumeDeviceHandleImpl*) hFloppy; + + if ( pItem == 0 ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_mountFloppy [pItem == 0]\n"); +#endif + + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_mountFloppy [invalid handle]\n"); +#endif + return osl_File_E_INVAL; + } + + bRet = osl_isFloppyMounted(pItem); + if ( bRet == sal_True ) + { +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"detected mounted floppy at '%s'\n",pItem->pszMountPoint); +#endif + return osl_File_E_BUSY; + } + + /* mfe: we can't use the mount(2) system call!!! */ + /* even if we are root */ + /* since mtab is not updated!!! */ + /* but we need it to be updated */ + /* some "magic" must be done */ + +/* nRet = mount(pItem->pszDevice,pItem->pszMountPoint,0,0,0); */ +/* if ( nRet != 0 ) */ +/* { */ +/* nRet=errno; */ +/* #ifdef DEBUG_OSL_FILE */ +/* perror("mount"); */ +/* #endif */ +/* } */ + + pszTmp = getenv("SAL_MOUNT_MOUNTPROG"); + if ( pszTmp != 0 ) + { + pszMountProg=pszTmp; + } + + pszTmp=getenv("SAL_MOUNT_SU_DO"); + if ( pszTmp != 0 ) + { + pszSuDo=pszTmp; + } + + if ( pszSuDo != 0 ) + { + snprintf(pszCmd, sizeof(pszCmd), "%s %s %s %s",pszSuDo,pszMountProg,pItem->pszDevice,pItem->pszMountPoint); + } + else + { + snprintf(pszCmd, sizeof(pszCmd), "%s %s",pszMountProg,pItem->pszMountPoint); + } + + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"executing '%s'\n",pszCmd); +#endif + + nRet = system(pszCmd); + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"call returned '%i'\n",nRet); + fprintf(stderr,"exit status is '%i'\n", WEXITSTATUS(nRet)); +#endif + + + switch ( WEXITSTATUS(nRet) ) + { + case 0: + nRet=0; + break; + + case 2: + nRet=EPERM; + break; + + case 4: + nRet=ENOENT; + break; + + case 8: + nRet=EINTR; + break; + + case 16: + nRet=EPERM; + break; + + case 32: + nRet=EBUSY; + break; + + case 64: + nRet=EAGAIN; + break; + + default: + nRet=EBUSY; + break; + } + + return ((0 == nRet) ? oslTranslateFileError(OSL_FET_SUCCESS, nRet) : oslTranslateFileError(OSL_FET_ERROR, nRet)); +} +#endif /* LINUX */ + + +#if defined(LINUX) +static oslFileError osl_unmountFloppy(oslVolumeDeviceHandle hFloppy) +{ + oslVolumeDeviceHandleImpl* pItem=0; + int nRet=0; + sal_Char pszCmd[PATH_MAX]; + sal_Char* pszTmp = 0; + sal_Char* pszSuDo = 0; + const sal_Char* pszUmountProg = "umount"; + + pszCmd[0] = '\0'; + +#ifdef TRACE_OSL_FILE + fprintf(stderr,"In osl_unmountFloppy\n"); +#endif + + pItem = (oslVolumeDeviceHandleImpl*) hFloppy; + + if ( pItem == 0 ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_unmountFloppy [pItem==0]\n"); +#endif + return osl_File_E_INVAL; + } + + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_unmountFloppy [invalid handle]\n"); +#endif + return osl_File_E_INVAL; + } + + /* mfe: we can't use the umount(2) system call!!! */ + /* even if we are root */ + /* since mtab is not updated!!! */ + /* but we need it to be updated */ + /* some "magic" must be done */ + +/* nRet=umount(pItem->pszDevice); */ +/* if ( nRet != 0 ) */ +/* { */ +/* nRet = errno; */ + +/* #ifdef DEBUG_OSL_FILE */ +/* perror("mount"); */ +/* #endif */ +/* } */ + + + pszTmp = getenv("SAL_MOUNT_UMOUNTPROG"); + if ( pszTmp != 0 ) + { + pszUmountProg=pszTmp; + } + + pszTmp = getenv("SAL_MOUNT_SU_DO"); + if ( pszTmp != 0 ) + { + pszSuDo=pszTmp; + } + + if ( pszSuDo != 0 ) + { + snprintf(pszCmd, sizeof(pszCmd), "%s %s %s",pszSuDo,pszUmountProg,pItem->pszMountPoint); + } + else + { + snprintf(pszCmd, sizeof(pszCmd), "%s %s",pszUmountProg,pItem->pszMountPoint); + } + + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"executing '%s'\n",pszCmd); +#endif + + nRet = system(pszCmd); + +#ifdef DEBUG_OSL_FILE + fprintf(stderr,"call returned '%i'\n",nRet); + fprintf(stderr,"exit status is '%i'\n", WEXITSTATUS(nRet)); +#endif + + switch ( WEXITSTATUS(nRet) ) + { + case 0: + nRet=0; + break; + + default: + nRet=EBUSY; + break; + } + +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Out osl_unmountFloppy [ok]\n"); +#endif + + return ((0 == nRet) ? oslTranslateFileError(OSL_FET_SUCCESS, nRet) : oslTranslateFileError(OSL_FET_ERROR, nRet)); + +/* return osl_File_E_None;*/ +} + +#endif /* LINUX */ + +#if defined(LINUX) +static sal_Bool +osl_getFloppyMountEntry(const sal_Char* pszPath, oslVolumeDeviceHandleImpl* pItem) +{ + struct mntent* pMountEnt; + FILE* pMountTab; + + pMountTab = setmntent (MOUNTTAB, "r"); + if (pMountTab == 0) + return sal_False; + + while ((pMountEnt = getmntent(pMountTab)) != 0) + { + if ( strncmp(pMountEnt->mnt_dir, pszPath, strlen(pMountEnt->mnt_dir)) == 0 + && strncmp(pMountEnt->mnt_fsname, "/dev/fd", strlen("/dev/fd")) == 0) + { + memset(pItem->pszMountPoint, 0, sizeof(pItem->pszMountPoint)); + strncpy(pItem->pszMountPoint, pMountEnt->mnt_dir, sizeof(pItem->pszMountPoint) - 1); + + memset(pItem->pszFilePath, 0, sizeof(pItem->pszFilePath)); + strncpy(pItem->pszFilePath, pMountEnt->mnt_dir, sizeof(pItem->pszFilePath) - 1); + + memset(pItem->pszDevice, 0, sizeof(pItem->pszDevice)); + strncpy(pItem->pszDevice, pMountEnt->mnt_fsname, sizeof(pItem->pszDevice) - 1); + + endmntent (pMountTab); + return sal_True; + } + } + + endmntent (pMountTab); + return sal_False; +} +#endif /* LINUX */ + +#if defined(LINUX) +static sal_Bool +osl_isFloppyMounted (oslVolumeDeviceHandleImpl* pDevice) +{ + oslVolumeDeviceHandleImpl aItem; + + if ( osl_getFloppyMountEntry (pDevice->pszMountPoint, &aItem) + && strcmp (aItem.pszMountPoint, pDevice->pszMountPoint) == 0 + && strcmp (aItem.pszDevice, pDevice->pszDevice) == 0) + { + return sal_True; + } + return sal_False; +} +#endif /* LINUX */ + +/* NetBSD floppy functions have to be added here. Until we have done that, + * we use the MACOSX definitions for nonexistent floppy. + * */ + +/****************************************************************************** + * + * MAC OS X FLOPPY FUNCTIONS + * + *****************************************************************************/ + +#if (defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) +static oslVolumeDeviceHandle osl_isFloppyDrive(const sal_Char* pszPath) +{ + return NULL; +} +#endif /* MACOSX */ + +#if ( defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) +static oslFileError osl_mountFloppy(oslVolumeDeviceHandle hFloppy) +{ + return osl_File_E_BUSY; +} +#endif /* MACOSX */ + +#if ( defined(MACOSX) || defined(NETBSD) || defined(FREEBSD)) +static oslFileError osl_unmountFloppy(oslVolumeDeviceHandle hFloppy) +{ + return osl_File_E_BUSY; +} +#endif /* MACOSX */ + +#if ( defined(NETBSD) || defined(FREEBSD) ) +static sal_Bool osl_getFloppyMountEntry(const sal_Char* pszPath, oslVolumeDeviceHandleImpl* pItem) +{ + return sal_False; +} +#endif /* NETBSD || FREEBSD */ + +#if ( defined(NETBSD) || defined(FREEBSD) ) +static sal_Bool osl_isFloppyMounted(oslVolumeDeviceHandleImpl* pDevice) +{ + return sal_False; +} +#endif /* NETBSD || FREEBSD */ + + +#ifdef DEBUG_OSL_FILE +static void osl_printFloppyHandle(oslVolumeDeviceHandleImpl* pItem) +{ + if (pItem == 0 ) + { + fprintf(stderr,"NULL Handle\n"); + return; + } + if ( pItem->ident[0] != 'O' || pItem->ident[1] != 'V' || pItem->ident[2] != 'D' || pItem->ident[3] != 'H' ) + { +#ifdef TRACE_OSL_FILE + fprintf(stderr,"Invalid Handle]\n"); +#endif + return; + } + + + fprintf(stderr,"MountPoint : '%s'\n",pItem->pszMountPoint); + fprintf(stderr,"FilePath : '%s'\n",pItem->pszFilePath); + fprintf(stderr,"Device : '%s'\n",pItem->pszDevice); + + return; +} +#endif diff --git a/sal/osl/unx/interlck.c b/sal/osl/unx/interlck.c new file mode 100644 index 000000000000..0342cdd983b4 --- /dev/null +++ b/sal/osl/unx/interlck.c @@ -0,0 +1,170 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/interlck.h> +#include <osl/diagnose.h> + +#if ( defined ( SOLARIS ) || defined ( NETBSD ) ) && defined ( SPARC ) +#error please use asm/interlck_sparc.s +#elif defined ( SOLARIS) && defined ( X86 ) +#error please use asm/interlck_x86.s +#elif defined ( GCC ) && ( defined ( X86 ) || defined ( X86_64 ) ) +/* That's possible on x86-64 too since oslInterlockedCount is a sal_Int32 */ + +extern int osl_isSingleCPU; + +/*****************************************************************************/ +/* osl_incrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount) +{ + register oslInterlockedCount nCount asm("%eax"); + + nCount = 1; + + if ( osl_isSingleCPU ) { + __asm__ __volatile__ ( + "xaddl %0, %1\n\t" + : "+r" (nCount), "+m" (*pCount) + : /* nothing */ + : "memory"); + } + else { + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %1\n\t" + : "+r" (nCount), "+m" (*pCount) + : /* nothing */ + : "memory"); + } + + return ++nCount; +} + +oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount) +{ + register oslInterlockedCount nCount asm("%eax"); + + nCount = -1; + + if ( osl_isSingleCPU ) { + __asm__ __volatile__ ( + "xaddl %0, %1\n\t" + : "+r" (nCount), "+m" (*pCount) + : /* nothing */ + : "memory"); + } + else { + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %1\n\t" + : "+r" (nCount), "+m" (*pCount) + : /* nothing */ + : "memory"); + } + + return --nCount; +} + +#elif defined ( GCC ) && defined ( POWERPC ) + +/*****************************************************************************/ +/* osl_incrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount) +{ + /* "addi" doesn't work with r0 as second parameter */ + register oslInterlockedCount nCount __asm__ ("r4"); + + __asm__ __volatile__ ( + "1: lwarx %0,0,%2\n\t" + " addi %0,%0,1\n\t" + " stwcx. %0,0,%2\n\t" + " bne- 1b\n\t" + " isync" + : "=&r" (nCount), "=m" (*pCount) + : "r" (pCount) + : "memory"); + + return nCount; +} + +oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount) +{ + /* "subi" doesn't work with r0 as second parameter */ + register oslInterlockedCount nCount __asm__ ("r4"); + + __asm__ __volatile__ ( + "1: lwarx %0,0,%2\n\t" + " subi %0,%0,1\n\t" + " stwcx. %0,0,%2\n\t" + " bne- 1b\n\t" + " isync" + : "=&r" (nCount), "=m" (*pCount) + : "r" (pCount) + : "memory"); + + return nCount; +} + +#else +/* use only if nothing else works, expensive due to single mutex for all reference counts */ + +static pthread_mutex_t InterLock = PTHREAD_MUTEX_INITIALIZER; + +/*****************************************************************************/ +/* osl_incrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount) +{ + oslInterlockedCount Count; + + pthread_mutex_lock(&InterLock); + Count = ++(*pCount); + pthread_mutex_unlock(&InterLock); + + return (Count); +} + +/*****************************************************************************/ +/* osl_decrementInterlockedCount */ +/*****************************************************************************/ +oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount) +{ + oslInterlockedCount Count; + + pthread_mutex_lock(&InterLock); + Count = --(*pCount); + pthread_mutex_unlock(&InterLock); + + return (Count); +} + +#endif /* default */ diff --git a/sal/osl/unx/makefile.mk b/sal/osl/unx/makefile.mk new file mode 100644 index 000000000000..1dd47fb4d19b --- /dev/null +++ b/sal/osl/unx/makefile.mk @@ -0,0 +1,189 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=sal +.IF "$(WORK_STAMP)"=="MIX364" +TARGET=cppsal +.ELSE +TARGET=cpposl +.ENDIF +USE_LDUMP2=TRUE + +PROJECTPCH4DLL=TRUE +PROJECTPCH=cont_pch +PROJECTPCHSOURCE=cont_pch + +TARGETTYPE=CUI + + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +CFLAGS+= $(LFS_CFLAGS) +CXXFLAGS+= $(LFS_CFLAGS) + +# --- Files -------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/conditn.obj \ + $(SLO)$/diagnose.obj \ + $(SLO)$/semaphor.obj \ + $(SLO)$/socket.obj \ + $(SLO)$/interlck.obj \ + $(SLO)$/mutex.obj \ + $(SLO)$/nlsupport.obj \ + $(SLO)$/thread.obj \ + $(SLO)$/module.obj \ + $(SLO)$/process.obj \ + $(SLO)$/security.obj \ + $(SLO)$/profile.obj \ + $(SLO)$/time.obj \ + $(SLO)$/signal.obj \ + $(SLO)$/pipe.obj \ + $(SLO)$/system.obj \ + $(SLO)$/util.obj \ + $(SLO)$/tempfile.obj\ + $(SLO)$/file.obj \ + $(SLO)$/file_misc.obj\ + $(SLO)$/file_url.obj\ + $(SLO)$/file_error_transl.obj\ + $(SLO)$/file_path_helper.obj\ + $(SLO)$/file_stat.obj \ + $(SLO)$/file_volume.obj \ + $(SLO)$/uunxapi.obj\ + $(SLO)$/process_impl.obj\ + $(SLO)$/salinit.obj + + +#.IF "$(UPDATER)"=="YES" +OBJFILES= $(OBJ)$/conditn.obj \ + $(OBJ)$/diagnose.obj \ + $(OBJ)$/semaphor.obj \ + $(OBJ)$/socket.obj \ + $(OBJ)$/interlck.obj \ + $(OBJ)$/mutex.obj \ + $(OBJ)$/nlsupport.obj \ + $(OBJ)$/thread.obj \ + $(OBJ)$/module.obj \ + $(OBJ)$/process.obj \ + $(OBJ)$/security.obj \ + $(OBJ)$/profile.obj \ + $(OBJ)$/time.obj \ + $(OBJ)$/signal.obj \ + $(OBJ)$/pipe.obj \ + $(OBJ)$/system.obj \ + $(OBJ)$/util.obj \ + $(OBJ)$/tempfile.obj\ + $(OBJ)$/file.obj \ + $(OBJ)$/file_misc.obj\ + $(OBJ)$/file_url.obj\ + $(OBJ)$/file_error_transl.obj\ + $(OBJ)$/file_path_helper.obj\ + $(OBJ)$/file_stat.obj \ + $(OBJ)$/file_volume.obj \ + $(OBJ)$/uunxapi.obj\ + $(OBJ)$/process_impl.obj\ + $(OBJ)$/salinit.obj + +#.ENDIF + +.IF "$(OS)"=="MACOSX" +SLOFILES += $(SLO)$/osxlocale.obj +.ENDIF + +.IF "$(OS)"=="SOLARIS" || "$(OS)"=="FREEBSD" || "$(OS)"=="NETBSD" || "$(OS)$(CPU)"=="LINUXS" || "$(OS)"=="MACOSX" +SLOFILES += $(SLO)$/backtrace.obj +OBJFILES += $(OBJ)$/backtrace.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.IF "$(COM)"=="C50" +APP1STDLIBS+=-lC +.ENDIF + +.IF "$(OS)" == "LINUX" +.IF "$(PAM)" == "NO" +CFLAGS+=-DNOPAM +.IF "$(NEW_SHADOW_API)" == "YES" +CFLAGS+=-DNEW_SHADOW_API +.ENDIF +.ENDIF +.IF "$(PAM_LINK)" == "YES" +CFLAGS+=-DPAM_LINK +.ENDIF +.IF "$(CRYPT_LINK)" == "YES" +CFLAGS+=-DCRYPT_LINK +.ENDIF +.ENDIF + +.IF "$(ENABLE_CRASHDUMP)" != "" || "$(PRODUCT)" == "" +CFLAGS+=-DSAL_ENABLE_CRASH_REPORT +.ENDIF + +.INCLUDE : target.mk + +.IF "$(OS)$(CPU)"=="SOLARISU" || "$(OS)$(CPU)"=="SOLARISS" || "$(OS)$(CPU)"=="NETBSDS" || "$(OS)$(CPU)"=="LINUXS" + +$(SLO)$/interlck.obj: $(SLO)$/interlck.o + touch $(SLO)$/interlck.obj + +$(OBJ)$/interlck.obj: $(OBJ)$/interlck.o + touch $(OBJ)$/interlck.obj + +$(SLO)$/interlck.o: $(MISC)$/interlck_sparc.s + $(ASM) $(AFLAGS) -o $@ $< + +$(OBJ)$/interlck.o: $(MISC)$/interlck_sparc.s + $(ASM) $(AFLAGS) -o $@ $< + +$(MISC)$/interlck_sparc.s: asm/interlck_sparc.s + tr -d "\015" < $< > $@ + +.ENDIF + +.IF "$(OS)$(CPU)"=="SOLARISI" + +$(SLO)$/interlck.obj: $(SLO)$/interlck.o + touch $(SLO)$/interlck.obj + +$(OBJ)$/interlck.obj: $(OBJ)$/interlck.o + touch $(OBJ)$/interlck.obj + +$(SLO)$/interlck.o: $(MISC)$/interlck_x86.s + $(ASM) $(AFLAGS) -o $@ $< + +$(OBJ)$/interlck.o: $(MISC)$/interlck_x86.s + $(ASM) $(AFLAGS) -o $@ $< + +$(MISC)$/interlck_x86.s: asm/interlck_x86.s + tr -d "\015" < $< > $@ + +.ENDIF diff --git a/sal/osl/unx/module.c b/sal/osl/unx/module.c new file mode 100644 index 000000000000..8f8f76a8656c --- /dev/null +++ b/sal/osl/unx/module.c @@ -0,0 +1,242 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <sal/types.h> +#include <osl/diagnose.h> +#include <osl/module.h> +#include <osl/thread.h> +#include <osl/process.h> +#include <osl/file.h> + +#include "system.h" + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +/* implemented in file.c */ +extern int UnicodeToText(char *, size_t, const sal_Unicode *, sal_Int32); + +oslModule SAL_CALL osl_psz_loadModule(const sal_Char *pszModuleName, sal_Int32 nRtldMode); + +/*****************************************************************************/ +/* osl_loadModule */ +/*****************************************************************************/ + +oslModule SAL_CALL osl_loadModule(rtl_uString *ustrModuleName, sal_Int32 nRtldMode) +{ + oslModule pModule=0; + rtl_uString* ustrTmp = NULL; + + OSL_ENSURE(ustrModuleName,"osl_loadModule : string is not valid"); + + /* ensure ustrTmp hold valid string */ + if (osl_File_E_None != osl_getSystemPathFromFileURL(ustrModuleName, &ustrTmp)) + rtl_uString_assign(&ustrTmp, ustrModuleName); + + if (ustrTmp) + { + char buffer[PATH_MAX]; + + if (UnicodeToText(buffer, PATH_MAX, ustrTmp->buffer, ustrTmp->length)) + pModule = osl_psz_loadModule(buffer, nRtldMode); + rtl_uString_release(ustrTmp); + } + + return pModule; +} + +/*****************************************************************************/ +/* osl_psz_loadModule */ +/*****************************************************************************/ + +oslModule SAL_CALL osl_psz_loadModule(const sal_Char *pszModuleName, sal_Int32 nRtldMode) +{ + OSL_ASSERT( + (nRtldMode & SAL_LOADMODULE_LAZY) == 0 || + (nRtldMode & SAL_LOADMODULE_NOW) == 0); /* only either LAZY or NOW */ + if (pszModuleName) + { +#ifndef NO_DL_FUNCTIONS + int rtld_mode = + ((nRtldMode & SAL_LOADMODULE_NOW) ? RTLD_NOW : RTLD_LAZY) | + ((nRtldMode & SAL_LOADMODULE_GLOBAL) ? RTLD_GLOBAL : RTLD_LOCAL); + void* pLib = dlopen(pszModuleName, rtld_mode); + +#if OSL_DEBUG_LEVEL > 1 + if (pLib == 0) + OSL_TRACE("Error osl_loadModule: %s\n", dlerror()); +#endif /* OSL_DEBUG_LEVEL */ + + return ((oslModule)(pLib)); + +#else /* NO_DL_FUNCTIONS */ + printf("No DL Functions\n"); +#endif /* NO_DL_FUNCTIONS */ + } + return NULL; +} + +/*****************************************************************************/ +/* osl_getModuleHandle */ +/*****************************************************************************/ + +sal_Bool SAL_CALL +osl_getModuleHandle(rtl_uString *pModuleName, oslModule *pResult) +{ + (void) pModuleName; /* avoid warning about unused parameter */ + *pResult = (oslModule) RTLD_DEFAULT; + return sal_True; +} + +/*****************************************************************************/ +/* osl_unloadModule */ +/*****************************************************************************/ +void SAL_CALL osl_unloadModule(oslModule hModule) +{ + if (hModule) + { +#ifndef NO_DL_FUNCTIONS + int nRet = dlclose(hModule); + +#if OSL_DEBUG_LEVEL > 1 + if (nRet != 0) + { + fprintf(stderr, "Error osl_unloadModule: %s\n", dlerror()); + } +#else + (void) nRet; +#endif /* if OSL_DEBUG_LEVEL */ + +#endif /* ifndef NO_DL_FUNCTIONS */ + } +} + +/*****************************************************************************/ +/* osl_getSymbol */ +/*****************************************************************************/ +void* SAL_CALL +osl_getSymbol(oslModule Module, rtl_uString* pSymbolName) +{ + return (void *) osl_getFunctionSymbol(Module, pSymbolName); +} + + +/*****************************************************************************/ +/* osl_getAsciiFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL +osl_getAsciiFunctionSymbol(oslModule Module, const sal_Char *pSymbol) +{ + void *fcnAddr = NULL; + +#ifndef NO_DL_FUNCTIONS + if (pSymbol) + { + fcnAddr = dlsym(Module, pSymbol); + + if (!fcnAddr) + OSL_TRACE("Error osl_getAsciiFunctionSymbol: %s\n", dlerror()); + } +#endif + + return (oslGenericFunction) fcnAddr; +} + +/*****************************************************************************/ +/* osl_getFunctionSymbol */ +/*****************************************************************************/ +oslGenericFunction SAL_CALL +osl_getFunctionSymbol(oslModule module, rtl_uString *puFunctionSymbolName) +{ + oslGenericFunction pSymbol = NULL; + + if( puFunctionSymbolName ) + { + rtl_String* pSymbolName = NULL; + + rtl_uString2String( &pSymbolName, + rtl_uString_getStr(puFunctionSymbolName), + rtl_uString_getLength(puFunctionSymbolName), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( pSymbolName != NULL ) + { + pSymbol = osl_getAsciiFunctionSymbol(module, rtl_string_getStr(pSymbolName)); + rtl_string_release(pSymbolName); + } + } + + return pSymbol; +} + +/*****************************************************************************/ +/* osl_getModuleURLFromAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromAddress(void * addr, rtl_uString ** ppLibraryUrl) +{ + sal_Bool result = sal_False; + Dl_info dl_info; + + if ((result = dladdr(addr, &dl_info)) != 0) + { + rtl_uString * workDir = NULL; + osl_getProcessWorkingDir(&workDir); + if (workDir) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE("module.c::osl_getModuleURLFromAddress - %s\n", dl_info.dli_fname); +#endif + rtl_string2UString(ppLibraryUrl, + dl_info.dli_fname, + strlen(dl_info.dli_fname), + osl_getThreadTextEncoding(), + OSTRING_TO_OUSTRING_CVTFLAGS); + + OSL_ASSERT(*ppLibraryUrl != NULL); + osl_getFileURLFromSystemPath(*ppLibraryUrl, ppLibraryUrl); + osl_getAbsoluteFileURL(workDir, *ppLibraryUrl, ppLibraryUrl); + + rtl_uString_release(workDir); + result = sal_True; + } + else + { + result = sal_False; + } + } + return result; +} + +/*****************************************************************************/ +/* osl_getModuleURLFromFunctionAddress */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress(oslGenericFunction addr, rtl_uString ** ppLibraryUrl) +{ + return osl_getModuleURLFromAddress((void*)addr, ppLibraryUrl); +} diff --git a/sal/osl/unx/mutex.c b/sal/osl/unx/mutex.c new file mode 100644 index 000000000000..2f47ba8791ad --- /dev/null +++ b/sal/osl/unx/mutex.c @@ -0,0 +1,221 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/mutex.h> +#include <osl/diagnose.h> + +#include <pthread.h> +#include <stdlib.h> + +#if defined LINUX /* bad hack */ +int pthread_mutexattr_setkind_np(pthread_mutexattr_t *, int); +#define pthread_mutexattr_settype pthread_mutexattr_setkind_np +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#endif + +/* + Implementation notes: + oslMutex hides a pointer to the oslMutexImpl structure, which + ist needed to manage recursive locks on a mutex. + +*/ + +typedef struct _oslMutexImpl +{ + pthread_mutex_t mutex; +} oslMutexImpl; + + +/*****************************************************************************/ +/* osl_createMutex */ +/*****************************************************************************/ +oslMutex SAL_CALL osl_createMutex() +{ + oslMutexImpl* pMutex = (oslMutexImpl*) malloc(sizeof(oslMutexImpl)); + pthread_mutexattr_t aMutexAttr; + int nRet=0; + + OSL_ASSERT(pMutex); + + if ( pMutex == 0 ) + { + return 0; + } + + pthread_mutexattr_init(&aMutexAttr); + + nRet = pthread_mutexattr_settype(&aMutexAttr, PTHREAD_MUTEX_RECURSIVE); + + nRet = pthread_mutex_init(&(pMutex->mutex), &aMutexAttr); + if ( nRet != 0 ) + { + OSL_TRACE("osl_createMutex : mutex init failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + + free(pMutex); + pMutex = 0; + } + + pthread_mutexattr_destroy(&aMutexAttr); + + return (oslMutex) pMutex; +} + +/*****************************************************************************/ +/* osl_destroyMutex */ +/*****************************************************************************/ +void SAL_CALL osl_destroyMutex(oslMutex Mutex) +{ + oslMutexImpl* pMutex = (oslMutexImpl*) Mutex; + + OSL_ASSERT(pMutex); + + if ( pMutex != 0 ) + { + int nRet=0; + + nRet = pthread_mutex_destroy(&(pMutex->mutex)); + if ( nRet != 0 ) + { + OSL_TRACE("osl_destroyMutex : mutex destroy failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + } + + free(pMutex); + } + + return; +} + +/*****************************************************************************/ +/* osl_acquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireMutex(oslMutex Mutex) +{ + oslMutexImpl* pMutex = (oslMutexImpl*) Mutex; + + OSL_ASSERT(pMutex); + + if ( pMutex != 0 ) + { + int nRet=0; + + nRet = pthread_mutex_lock(&(pMutex->mutex)); + if ( nRet != 0 ) + { + OSL_TRACE("osl_acquireMutex : mutex lock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + return sal_True; + } + + /* not initialized */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_tryToAcquireMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireMutex(oslMutex Mutex) +{ + oslMutexImpl* pMutex = (oslMutexImpl*) Mutex; + + OSL_ASSERT(pMutex); + + if ( pMutex ) + { + int nRet = 0; + nRet = pthread_mutex_trylock(&(pMutex->mutex)); + if ( nRet != 0 ) + return sal_False; + + return sal_True; + } + + /* not initialized */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_releaseMutex */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseMutex(oslMutex Mutex) +{ + oslMutexImpl* pMutex = (oslMutexImpl*) Mutex; + + OSL_ASSERT(pMutex); + + if ( pMutex ) + { + int nRet=0; + nRet = pthread_mutex_unlock(&(pMutex->mutex)); + if ( nRet != 0 ) + { + OSL_TRACE("osl_releaseMutex : mutex unlock failed. Errno: %d; %s\n", + nRet, strerror(nRet)); + return sal_False; + } + + return sal_True; + } + + /* not initialized */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_getGlobalMutex */ +/*****************************************************************************/ + +static oslMutexImpl globalMutexImpl; + +static void globalMutexInitImpl(void) { + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr) != 0 || + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) || + pthread_mutex_init(&globalMutexImpl.mutex, &attr) != 0 || + pthread_mutexattr_destroy(&attr) != 0) + { + abort(); + } +} + +oslMutex * SAL_CALL osl_getGlobalMutex() +{ + /* necessary to get a "oslMutex *" */ + static oslMutex globalMutex = (oslMutex) &globalMutexImpl; + + static pthread_once_t once = PTHREAD_ONCE_INIT; + if (pthread_once(&once, &globalMutexInitImpl) != 0) { + abort(); + } + + return &globalMutex; +} diff --git a/sal/osl/unx/nlsupport.c b/sal/osl/unx/nlsupport.c new file mode 100644 index 000000000000..c9f4fd18df21 --- /dev/null +++ b/sal/osl/unx/nlsupport.c @@ -0,0 +1,949 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <osl/nlsupport.h> +#include <osl/diagnose.h> +#include <osl/process.h> +#include <rtl/memory.h> + +#if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) || defined(MACOSX) +#include <pthread.h> +#ifndef MACOSX + #include <locale.h> + #include <langinfo.h> +#else +#include <osl/module.h> +#include <osl/thread.h> +#endif /* !MACOSX */ +#endif /* LINUX || SOLARIS || NETBSD || MACOSX */ + +#include <string.h> + +/***************************************************************************** + typedefs + *****************************************************************************/ + + +typedef struct { + const char *key; + const rtl_TextEncoding value; +} _pair; + + +/***************************************************************************** + compare function for binary search + *****************************************************************************/ + +static int +_pair_compare (const char *key, const _pair *pair) +{ + int result = rtl_str_compareIgnoreAsciiCase( key, pair->key ); + return result; +} + +/***************************************************************************** + binary search on encoding tables + *****************************************************************************/ + +static const _pair* +_pair_search (const char *key, const _pair *base, unsigned int member ) +{ + unsigned int lower = 0; + unsigned int upper = member; + unsigned int current; + int comparison; + + /* check for validity of input */ + if ( (key == NULL) || (base == NULL) || (member == 0) ) + return NULL; + + /* binary search */ + while ( lower < upper ) + { + current = (lower + upper) / 2; + comparison = _pair_compare( key, base + current ); + if (comparison < 0) + upper = current; + else if (comparison > 0) + lower = current + 1; + else + return base + current; + } + + return NULL; +} + + +/***************************************************************************** + convert rtl_Locale to locale string + *****************************************************************************/ + +static char * _compose_locale( rtl_Locale * pLocale, char * buffer, size_t n ) +{ + /* check if a valid locale is specified */ + if( pLocale && pLocale->Language && + (pLocale->Language->length == 2 || pLocale->Language->length == 3) ) + { + size_t offset = 0; + + /* convert language code to ascii */ + { + rtl_String *pLanguage = NULL; + + rtl_uString2String( &pLanguage, + pLocale->Language->buffer, pLocale->Language->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( SAL_INT_CAST(sal_uInt32, pLanguage->length) < n ) + { + strcpy( buffer, pLanguage->buffer ); + offset = pLanguage->length; + } + + rtl_string_release( pLanguage ); + } + + /* convert country code to ascii */ + if( pLocale->Country && (pLocale->Country->length == 2) ) + { + rtl_String *pCountry = NULL; + + rtl_uString2String( &pCountry, + pLocale->Country->buffer, pLocale->Country->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( offset + pCountry->length + 1 < n ) + { + strcpy( buffer + offset++, "_" ); + strcpy( buffer + offset, pCountry->buffer ); + offset += pCountry->length; + } + + rtl_string_release( pCountry ); + } + + /* convert variant to ascii - check if there is enough space for the variant string */ + if( pLocale->Variant && pLocale->Variant->length && + ( SAL_INT_CAST(sal_uInt32, pLocale->Variant->length) < n - 6 ) ) + { + rtl_String *pVariant = NULL; + + rtl_uString2String( &pVariant, + pLocale->Variant->buffer, pLocale->Variant->length, + RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); + + if( offset + pVariant->length + 1 < n ) + { + strcpy( buffer + offset, pVariant->buffer ); + offset += pVariant->length; + } + + rtl_string_release( pVariant ); + } + + return buffer; + } + + return NULL; +} + +/***************************************************************************** + convert locale string to rtl_Locale + *****************************************************************************/ + +static rtl_Locale * _parse_locale( const char * locale ) +{ + static sal_Unicode c_locale[2] = { (sal_Unicode) 'C', 0 }; + + /* check if locale contains a valid string */ + if( locale ) + { + size_t len = strlen( locale ); + + if( len >= 2 ) + { + rtl_uString * pLanguage = NULL; + rtl_uString * pCountry = NULL; + rtl_uString * pVariant = NULL; + + size_t offset = 2; + + rtl_Locale * ret; + + /* language is a two or three letter code */ + if( (len > 3 && '_' == locale[3]) || (len == 3 && '_' != locale[2]) ) + offset = 3; + + /* convert language code to unicode */ + rtl_string2UString( &pLanguage, locale, offset, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pLanguage != NULL); + + /* convert country code to unicode */ + if( len >= offset+3 && '_' == locale[offset] ) + { + rtl_string2UString( &pCountry, locale + offset + 1, 2, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pCountry != NULL); + offset += 3; + } + + /* convert variant code to unicode - do not rely on "." as delimiter */ + if( len > offset ) { + rtl_string2UString( &pVariant, locale + offset, len - offset, RTL_TEXTENCODING_ASCII_US, OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(pVariant != NULL); + } + + ret = rtl_locale_register( pLanguage->buffer, pCountry ? pCountry->buffer : c_locale + 1, pVariant ? pVariant->buffer : c_locale + 1 ); + + if (pVariant) rtl_uString_release(pVariant); + if (pCountry) rtl_uString_release(pCountry); + if (pLanguage) rtl_uString_release(pLanguage); + + return ret; + } + else + return rtl_locale_register( c_locale, c_locale + 1, c_locale + 1 ); + } + + return NULL; +} + +#if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) + +/* + * This implementation of osl_getTextEncodingFromLocale maps + * from nl_langinfo(CODESET) to rtl_textencoding defines. + * nl_langinfo() is supported only on Linux, Solaris, + * >= NetBSD 1.6 and >= FreeBSD 4.4 + * + * This routine is SLOW because of the setlocale call, so + * grab the result and cache it. + * + * XXX this code has the usual mt problems aligned with setlocale() XXX + */ + +#ifdef LINUX +#if !defined(CODESET) +#define CODESET _NL_CTYPE_CODESET_NAME +#endif +#endif + +/* + * _nl_language_list[] is an array list of supported encodings. Because + * we are using a binary search, the list has to be in ascending order. + * We are comparing the encodings case insensitiv, so the list has + * to be completly upper- , or lowercase. + */ + +#if defined(SOLARIS) + +/* The values in the below list can be obtained with a script like + * #!/bin/sh + * for i in `locale -a`; do + * LC_ALL=$i locale -k code_set_name + * done + */ +const _pair _nl_language_list[] = { + { "5601", RTL_TEXTENCODING_EUC_KR }, /* ko_KR.EUC */ + { "646", RTL_TEXTENCODING_ISO_8859_1 }, /* fake: ASCII_US */ + { "ANSI-1251", RTL_TEXTENCODING_MS_1251 }, /* ru_RU.ANSI1251 */ + { "BIG5", RTL_TEXTENCODING_BIG5 }, /* zh_CN.BIG5 */ + { "BIG5-HKSCS", RTL_TEXTENCODING_BIG5_HKSCS }, /* zh_CN.BIG5HK */ + { "CNS11643", RTL_TEXTENCODING_EUC_TW }, /* zh_TW.EUC */ + { "EUCJP", RTL_TEXTENCODING_EUC_JP }, /* ja_JP.eucjp */ + { "GB18030", RTL_TEXTENCODING_GB_18030 }, /* zh_CN.GB18030 */ + { "GB2312", RTL_TEXTENCODING_GB_2312 }, /* zh_CN */ + { "GBK", RTL_TEXTENCODING_GBK }, /* zh_CN.GBK */ + { "ISO8859-1", RTL_TEXTENCODING_ISO_8859_1 }, + { "ISO8859-10", RTL_TEXTENCODING_ISO_8859_10 }, + { "ISO8859-13", RTL_TEXTENCODING_ISO_8859_13 }, /* lt_LT lv_LV */ + { "ISO8859-14", RTL_TEXTENCODING_ISO_8859_14 }, + { "ISO8859-15", RTL_TEXTENCODING_ISO_8859_15 }, + { "ISO8859-2", RTL_TEXTENCODING_ISO_8859_2 }, + { "ISO8859-3", RTL_TEXTENCODING_ISO_8859_3 }, + { "ISO8859-4", RTL_TEXTENCODING_ISO_8859_4 }, + { "ISO8859-5", RTL_TEXTENCODING_ISO_8859_5 }, + { "ISO8859-6", RTL_TEXTENCODING_ISO_8859_6 }, + { "ISO8859-7", RTL_TEXTENCODING_ISO_8859_7 }, + { "ISO8859-8", RTL_TEXTENCODING_ISO_8859_8 }, + { "ISO8859-9", RTL_TEXTENCODING_ISO_8859_9 }, + { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, + { "KOI8-U", RTL_TEXTENCODING_KOI8_U }, + { "PCK", RTL_TEXTENCODING_MS_932 }, + { "SUN_EU_GREEK", RTL_TEXTENCODING_ISO_8859_7 }, /* 8859-7 + Euro */ + { "TIS620.2533", RTL_TEXTENCODING_MS_874 }, /* th_TH.TIS620 */ + { "UTF-8", RTL_TEXTENCODING_UTF8 } +}; + +/* XXX MS-874 is an extension to tis620, so this is not + * really equivalent */ + +#elif defined(LINUX) || defined(NETBSD) + +const _pair _nl_language_list[] = { + { "ANSI_X3.110-1983", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-99 NAPLPS */ + { "ANSI_X3.4-1968", RTL_TEXTENCODING_ISO_8859_1 }, /* fake: ASCII_US */ + { "ASMO_449", RTL_TEXTENCODING_DONTKNOW }, /* ISO_9036 ARABIC7 */ + { "BALTIC", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-179 */ + { "BIG5", RTL_TEXTENCODING_BIG5 }, /* locale: zh_TW */ + { "BIG5-HKSCS", RTL_TEXTENCODING_BIG5_HKSCS }, /* locale: zh_CN.BIG5HK */ + { "BIG5HKSCS", RTL_TEXTENCODING_BIG5_HKSCS }, /* depricated */ + { "BS_4730", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-4 ISO646-GB */ + { "BS_VIEWDATA", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-47 */ + { "CP1250", RTL_TEXTENCODING_MS_1250 }, /* MS-EE */ + { "CP1251", RTL_TEXTENCODING_MS_1251 }, /* MS-CYRL */ + { "CP1252", RTL_TEXTENCODING_MS_1252 }, /* MS-ANSI */ + { "CP1253", RTL_TEXTENCODING_MS_1253 }, /* MS-GREEK */ + { "CP1254", RTL_TEXTENCODING_MS_1254 }, /* MS-TURK */ + { "CP1255", RTL_TEXTENCODING_MS_1255 }, /* MS-HEBR */ + { "CP1256", RTL_TEXTENCODING_MS_1256 }, /* MS-ARAB */ + { "CP1257", RTL_TEXTENCODING_MS_1257 }, /* WINBALTRIM */ + { "CSA_Z243.4-1985-1", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-121 */ + { "CSA_Z243.4-1985-2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-122 CSA7-2 */ + { "CSA_Z243.4-1985-GR", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-123 */ + { "CSN_369103", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-139 */ + { "CWI", RTL_TEXTENCODING_DONTKNOW }, /* CWI-2 CP-HU */ + { "DEC-MCS", RTL_TEXTENCODING_DONTKNOW }, /* DEC */ + { "DIN_66003", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-21 */ + { "DS_2089", RTL_TEXTENCODING_DONTKNOW }, /* DS2089 ISO646-DK */ + { "EBCDIC-AT-DE", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-AT-DE-A", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-CA-FR", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-DK-NO", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-DK-NO-A", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-ES", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-ES-A", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-ES-S", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-FI-SE", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-FI-SE-A", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-FR", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-IS-FRISS", RTL_TEXTENCODING_DONTKNOW }, /* FRISS */ + { "EBCDIC-IT", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-PT", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-UK", RTL_TEXTENCODING_DONTKNOW }, + { "EBCDIC-US", RTL_TEXTENCODING_DONTKNOW }, + { "ECMA-CYRILLIC", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-111 */ + { "ES", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-17 */ + { "ES2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-85 */ + { "EUC-JP", RTL_TEXTENCODING_EUC_JP }, /* locale: ja_JP.eucjp */ + { "EUC-KR", RTL_TEXTENCODING_EUC_KR }, /* locale: ko_KR.euckr */ + { "EUC-TW", RTL_TEXTENCODING_EUC_TW }, /* locale: zh_TW.euctw */ + { "GB18030", RTL_TEXTENCODING_GB_18030 }, /* locale: zh_CN.gb18030 */ + { "GB2312", RTL_TEXTENCODING_GB_2312 }, /* locale: zh_CN */ + { "GB_1988-80", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-57 */ + { "GBK", RTL_TEXTENCODING_GBK }, /* locale: zh_CN.GBK */ + { "GOST_19768-74", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-153 */ + { "GREEK-CCITT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-150 */ + { "GREEK7", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-88 */ + { "GREEK7-OLD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-18 */ + { "HP-ROMAN8", RTL_TEXTENCODING_DONTKNOW }, /* ROMAN8 R8 */ + { "IBM037", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-[US|CA|WT] */ + { "IBM038", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-INT CP038 */ + { "IBM1004", RTL_TEXTENCODING_DONTKNOW }, /* CP1004 OS2LATIN1 */ + { "IBM1026", RTL_TEXTENCODING_DONTKNOW }, /* CP1026 1026 */ + { "IBM1047", RTL_TEXTENCODING_DONTKNOW }, /* CP1047 1047 */ + { "IBM256", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-INT1 */ + { "IBM273", RTL_TEXTENCODING_DONTKNOW }, /* CP273 */ + { "IBM274", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-BE CP274 */ + { "IBM275", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-BR CP275 */ + { "IBM277", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-[DK|NO] */ + { "IBM278", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-[FISE]*/ + { "IBM280", RTL_TEXTENCODING_DONTKNOW }, /* CP280 EBCDIC-CP-IT*/ + { "IBM281", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-JP-E CP281 */ + { "IBM284", RTL_TEXTENCODING_DONTKNOW }, /* CP284 EBCDIC-CP-ES */ + { "IBM285", RTL_TEXTENCODING_DONTKNOW }, /* CP285 EBCDIC-CP-GB */ + { "IBM290", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-JP-KANA */ + { "IBM297", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-FR */ + { "IBM420", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-AR1 */ + { "IBM423", RTL_TEXTENCODING_DONTKNOW }, /* CP423 EBCDIC-CP-GR */ + { "IBM424", RTL_TEXTENCODING_DONTKNOW }, /* CP424 EBCDIC-CP-HE */ + { "IBM437", RTL_TEXTENCODING_IBM_437 }, /* CP437 437 */ + { "IBM500", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CP-[BE|CH] */ + { "IBM850", RTL_TEXTENCODING_IBM_850 }, /* CP850 850 */ + { "IBM851", RTL_TEXTENCODING_DONTKNOW }, /* CP851 851 */ + { "IBM852", RTL_TEXTENCODING_IBM_852 }, /* CP852 852 */ + { "IBM855", RTL_TEXTENCODING_IBM_855 }, /* CP855 855 */ + { "IBM857", RTL_TEXTENCODING_IBM_857 }, /* CP857 857 */ + { "IBM860", RTL_TEXTENCODING_IBM_860 }, /* CP860 860 */ + { "IBM861", RTL_TEXTENCODING_IBM_861 }, /* CP861 861 CP-IS */ + { "IBM862", RTL_TEXTENCODING_IBM_862 }, /* CP862 862 */ + { "IBM863", RTL_TEXTENCODING_IBM_863 }, /* CP863 863 */ + { "IBM864", RTL_TEXTENCODING_IBM_864 }, /* CP864 */ + { "IBM865", RTL_TEXTENCODING_IBM_865 }, /* CP865 865 */ + { "IBM866", RTL_TEXTENCODING_IBM_866 }, /* CP866 866 */ + { "IBM868", RTL_TEXTENCODING_DONTKNOW }, /* CP868 CP-AR */ + { "IBM869", RTL_TEXTENCODING_IBM_869 }, /* CP869 869 CP-GR */ + { "IBM870", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-[ROECE|YU] */ + { "IBM871", RTL_TEXTENCODING_DONTKNOW }, /* CP871 EBCDIC-CP-IS */ + { "IBM875", RTL_TEXTENCODING_DONTKNOW }, /* CP875 EBCDIC-GREEK */ + { "IBM880", RTL_TEXTENCODING_DONTKNOW }, /* EBCDIC-CYRILLIC */ + { "IBM891", RTL_TEXTENCODING_DONTKNOW }, /* CP891 */ + { "IBM903", RTL_TEXTENCODING_DONTKNOW }, /* CP903 */ + { "IBM904", RTL_TEXTENCODING_DONTKNOW }, /* CP904 904 */ + { "IBM905", RTL_TEXTENCODING_DONTKNOW }, /* CP905 EBCDIC-CP-TR */ + { "IBM918", RTL_TEXTENCODING_DONTKNOW }, /* CP918 EBCDIC-AR2 */ + { "IEC_P27-1", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-143 */ + { "INIS", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-49 */ + { "INIS-8", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-50 */ + { "INIS-CYRILLIC", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-51 */ + { "INVARIANT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-170 */ + { "ISO-8859-1", RTL_TEXTENCODING_ISO_8859_1 }, /* ISO-IR-100 CP819 */ + { "ISO-8859-10", RTL_TEXTENCODING_ISO_8859_10 }, /* ISO-IR-157 LATIN6 */ + { "ISO-8859-13", RTL_TEXTENCODING_ISO_8859_13 }, /* ISO-IR-179 LATIN7 */ + { "ISO-8859-14", RTL_TEXTENCODING_ISO_8859_14 }, /* LATIN8 L8 */ + { "ISO-8859-15", RTL_TEXTENCODING_ISO_8859_15 }, + { "ISO-8859-2", RTL_TEXTENCODING_ISO_8859_2 }, /* LATIN2 L2 */ + { "ISO-8859-3", RTL_TEXTENCODING_ISO_8859_3 }, /* LATIN3 L3 */ + { "ISO-8859-4", RTL_TEXTENCODING_ISO_8859_4 }, /* LATIN4 L4 */ + { "ISO-8859-5", RTL_TEXTENCODING_ISO_8859_5 }, /* CYRILLIC */ + { "ISO-8859-6", RTL_TEXTENCODING_ISO_8859_6 }, /* ECMA-114 ARABIC */ + { "ISO-8859-7", RTL_TEXTENCODING_ISO_8859_7 }, /* ECMA-118 GREEK8 */ + { "ISO-8859-8", RTL_TEXTENCODING_ISO_8859_8 }, /* ISO_8859-8 HEBREW */ + { "ISO-8859-9", RTL_TEXTENCODING_ISO_8859_9 }, /* ISO_8859-9 LATIN5 */ + { "ISO-IR-90", RTL_TEXTENCODING_DONTKNOW }, /* ISO_6937-2:1983 */ + { "ISO_10367-BOX", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-155 */ + { "ISO_2033-1983", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-98 E13B */ + { "ISO_5427", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-37 KOI-7 */ + { "ISO_5427-EXT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-54 */ + { "ISO_5428", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-55 */ + { "ISO_646.BASIC", RTL_TEXTENCODING_ASCII_US }, /* REF */ + { "ISO_646.IRV", RTL_TEXTENCODING_ASCII_US }, /* ISO-IR-2 IRV */ + { "ISO_646.IRV:1983", RTL_TEXTENCODING_ISO_8859_1 }, /* fake: ASCII_US, used for "C" locale*/ + { "ISO_6937", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-156 ISO6937*/ + { "ISO_6937-2-25", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-152 */ + { "ISO_6937-2-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-142 */ + { "ISO_8859-SUPP", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-154 */ + { "IT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-15 */ + { "JIS_C6220-1969-JP", RTL_TEXTENCODING_DONTKNOW }, /* KATAKANA X0201-7 */ + { "JIS_C6220-1969-RO", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-14 */ + { "JIS_C6229-1984-A", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-91 */ + { "JIS_C6229-1984-B", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-92 */ + { "JIS_C6229-1984-B-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-93 */ + { "JIS_C6229-1984-HAND", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-94 */ + { "JIS_C6229-1984-HAND-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-95 */ + { "JIS_C6229-1984-KANA", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-96 */ + { "JIS_X0201", RTL_TEXTENCODING_DONTKNOW }, /* X0201 */ + { "JUS_I.B1.002", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-141 */ + { "JUS_I.B1.003-MAC", RTL_TEXTENCODING_DONTKNOW }, /* MACEDONIAN */ + { "JUS_I.B1.003-SERB", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-146 SERBIAN */ + { "KOI-8", RTL_TEXTENCODING_DONTKNOW }, + { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, + { "KOI8-U", RTL_TEXTENCODING_KOI8_U }, + { "KSC5636", RTL_TEXTENCODING_DONTKNOW }, /* ISO646-KR */ + { "LATIN-GREEK", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-19 */ + { "LATIN-GREEK-1", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-27 */ + { "MAC-IS", RTL_TEXTENCODING_APPLE_ROMAN }, + { "MAC-UK", RTL_TEXTENCODING_APPLE_ROMAN }, + { "MACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN }, /* MAC */ + { "MSZ_7795.3", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-86 */ + { "NATS-DANO", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-9-1 */ + { "NATS-DANO-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-9-2 */ + { "NATS-SEFI", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-8-1 */ + { "NATS-SEFI-ADD", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-8-2 */ + { "NC_NC00-10", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-151 */ + { "NEXTSTEP", RTL_TEXTENCODING_DONTKNOW }, /* NEXT */ + { "NF_Z_62-010", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-69 */ + { "NF_Z_62-010_(1973)", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-25 */ + { "NS_4551-1", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-60 */ + { "NS_4551-2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-61 */ + { "PT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-16 */ + { "PT2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-84 */ + { "SAMI", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-158 */ + { "SEN_850200_B", RTL_TEXTENCODING_DONTKNOW }, /* ISO646-[FI|SE] */ + { "SEN_850200_C", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-11 */ + { "T.101-G2", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-128 */ + { "T.61-7BIT", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-102 */ + { "T.61-8BIT", RTL_TEXTENCODING_DONTKNOW }, /* T.61 ISO-IR-103 */ + { "TIS-620", RTL_TEXTENCODING_MS_874 }, /* locale: th_TH */ + { "UTF-8", RTL_TEXTENCODING_UTF8 }, /* ISO-10646/UTF-8 */ + { "VIDEOTEX-SUPPL", RTL_TEXTENCODING_DONTKNOW }, /* ISO-IR-70 */ + { "WIN-SAMI-2", RTL_TEXTENCODING_DONTKNOW } /* WS2 */ +}; + +#elif defined(FREEBSD) + +const _pair _nl_language_list[] = { + { "ASCII", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "BIG5", RTL_TEXTENCODING_BIG5 }, /* China - Traditional Chinese */ + { "CP1251", RTL_TEXTENCODING_MS_1251 }, /* MS-CYRL */ + { "CP866", RTL_TEXTENCODING_IBM_866 }, /* CP866 866 */ + { "EUCCN", RTL_TEXTENCODING_EUC_CN }, /* China - Simplified Chinese */ + { "EUCJP", RTL_TEXTENCODING_EUC_JP }, /* Japan */ + { "EUCKR", RTL_TEXTENCODING_EUC_KR }, /* Korea */ + { "ISO8859-1", RTL_TEXTENCODING_ISO_8859_1 }, /* Western */ + { "ISO8859-15", RTL_TEXTENCODING_ISO_8859_15 }, /* Western Updated (w/Euro sign) */ + { "ISO8859-2", RTL_TEXTENCODING_ISO_8859_2 }, /* Central European */ + { "ISO8859-4", RTL_TEXTENCODING_ISO_8859_4 }, /* LATIN4 L4 */ + { "ISO8859-5", RTL_TEXTENCODING_ISO_8859_5 }, /* Cyrillic */ + { "ISO8859-7", RTL_TEXTENCODING_ISO_8859_7 }, /* Greek */ + { "ISO8859-9", RTL_TEXTENCODING_ISO_8859_9 }, /* Turkish */ + { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, /* KOI8-R */ + { "KOI8-U", RTL_TEXTENCODING_KOI8_U }, /* KOI8-U */ + { "SJIS", RTL_TEXTENCODING_SHIFT_JIS }, /* Japan */ + { "US-ASCII", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "UTF-8", RTL_TEXTENCODING_UTF8 } /* ISO-10646/UTF-8 */ +}; + +#elif defined(NETBSD) + +const _pair _nl_language_list[] = { + { "ASCII", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "BIG5", RTL_TEXTENCODING_BIG5 }, /* China - Traditional Chinese */ + { "CP1251", RTL_TEXTENCODING_MS_1251 }, /* MS-CYRL */ + { "CP866", RTL_TEXTENCODING_IBM_866 }, /* CP866 866 */ + { "CTEXT", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "EUCCN", RTL_TEXTENCODING_EUC_CN }, /* China - Simplified Chinese */ + { "EUCJP", RTL_TEXTENCODING_EUC_JP }, /* Japan */ + { "EUCKR", RTL_TEXTENCODING_EUC_KR }, /* Korea */ + { "EUCTW", RTL_TEXTENCODING_EUC_TW }, /* China - Traditional Chinese */ + { "ISO-2022-JP", RTL_TEXTENCODING_DONTKNOW }, /* */ + { "ISO-2022-JP-2", RTL_TEXTENCODING_DONTKNOW }, /* */ + { "ISO8859-1", RTL_TEXTENCODING_ISO_8859_1 }, /* Western */ + { "ISO8859-15", RTL_TEXTENCODING_ISO_8859_15 }, /* Western Updated (w/Euro sign) */ + { "ISO8859-2", RTL_TEXTENCODING_ISO_8859_2 }, /* Central European */ + { "ISO8859-4", RTL_TEXTENCODING_ISO_8859_4 }, /* LATIN4 L4 */ + { "ISO8859-5", RTL_TEXTENCODING_ISO_8859_5 }, /* Cyrillic */ + { "ISO8859-7", RTL_TEXTENCODING_ISO_8859_7 }, /* Greek */ + { "ISO8859-9", RTL_TEXTENCODING_ISO_8859_9 }, /* Turkish */ + { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, /* KOI8-R */ + { "KOI8-U", RTL_TEXTENCODING_KOI8_U }, /* KOI8-U */ + { "SJIS", RTL_TEXTENCODING_SHIFT_JIS }, /* Japan */ + { "US-ASCII", RTL_TEXTENCODING_ASCII_US }, /* US-ASCII */ + { "UTF-8", RTL_TEXTENCODING_UTF8 } /* ISO-10646/UTF-8 */ +}; + +#endif /* ifdef SOLARIS LINUX FREEBSD NETBSD */ + +static pthread_mutex_t aLocalMutex = PTHREAD_MUTEX_INITIALIZER; + +/***************************************************************************** + return the text encoding corresponding to the given locale + *****************************************************************************/ + +rtl_TextEncoding osl_getTextEncodingFromLocale( rtl_Locale * pLocale ) +{ + const _pair *language=0; + + char locale_buf[64] = ""; + char codeset_buf[64]; + + char *ctype_locale = 0; + char *codeset = 0; + + /* default to process locale if pLocale == NULL */ + if( NULL == pLocale ) + osl_getProcessLocale( &pLocale ); + + /* convert rtl_Locale to locale string */ + _compose_locale( pLocale, locale_buf, 64 ); + + /* basic thread safeness */ + pthread_mutex_lock( &aLocalMutex ); + + /* remember the charset as indicated by the LC_CTYPE locale */ + ctype_locale = setlocale( LC_CTYPE, NULL ); + + /* set the desired LC_CTYPE locale */ + if( NULL == setlocale( LC_CTYPE, locale_buf ) ) + { + pthread_mutex_unlock(&aLocalMutex); + return RTL_TEXTENCODING_DONTKNOW; + } + + /* get the charset as indicated by the LC_CTYPE locale */ +#if defined(NETBSD) && !defined(CODESET) + codeset = NULL; +#else + codeset = nl_langinfo( CODESET ); +#endif + + if ( codeset != NULL ) + { + /* get codeset into mt save memory */ + strncpy( codeset_buf, codeset, sizeof(codeset_buf) ); + codeset_buf[sizeof(codeset_buf) - 1] = 0; + codeset = codeset_buf; + } + + /* restore the original value of locale */ + if ( ctype_locale != NULL ) + setlocale( LC_CTYPE, ctype_locale ); + + pthread_mutex_unlock( &aLocalMutex ); + + /* search the codeset in our language list */ + if ( codeset != NULL ) + { + const unsigned int members = sizeof(_nl_language_list) / sizeof(_pair); + language = _pair_search (codeset, _nl_language_list, members); + } + + OSL_ASSERT( language && ( RTL_TEXTENCODING_DONTKNOW != language->value ) ); + + /* a matching item in our list provides a mapping from codeset to + * rtl-codeset */ + if ( language != NULL ) + return language->value; + + return RTL_TEXTENCODING_DONTKNOW; +} + +/***************************************************************************** + return the current process locale + *****************************************************************************/ + +void _imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + char * locale; + + /* basic thread safeness */ + pthread_mutex_lock( &aLocalMutex ); + + /* set the locale defined by the env vars */ + locale = setlocale( LC_CTYPE, "" ); + + /* fallback to the current locale */ + if( NULL == locale ) + locale = setlocale( LC_CTYPE, NULL ); + + /* return the LC_CTYPE locale */ + *ppLocale = _parse_locale( locale ); + + pthread_mutex_unlock( &aLocalMutex ); +} + +/***************************************************************************** + set the current process locale + *****************************************************************************/ + +int _imp_setProcessLocale( rtl_Locale * pLocale ) +{ + char locale_buf[64] = ""; + int ret = 0; + + /* convert rtl_Locale to locale string */ + _compose_locale( pLocale, locale_buf, 64 ); + + /* basic thread safeness */ + pthread_mutex_lock( &aLocalMutex ); + + /* try to set LC_ALL locale */ + if( NULL == setlocale( LC_ALL, locale_buf ) ) + ret = -1; + + pthread_mutex_unlock( &aLocalMutex ); + return ret; +} + +#else /* ifdef LINUX || SOLARIS || MACOSX || NETBSD */ + +/* + * This implementation of osl_getTextEncodingFromLocale maps + * from the ISO language codes. + */ + +const _pair _full_locale_list[] = { + { "ja_JP.eucJP", RTL_TEXTENCODING_EUC_JP }, + { "ja_JP.EUC", RTL_TEXTENCODING_EUC_JP }, + { "ko_KR.EUC", RTL_TEXTENCODING_EUC_KR }, + { "zh_CN.EUC", RTL_TEXTENCODING_EUC_CN }, + { "zh_TW.EUC", RTL_TEXTENCODING_EUC_TW } +}; + +const _pair _locale_extension_list[] = { + { "big5", RTL_TEXTENCODING_BIG5 }, + { "big5hk", RTL_TEXTENCODING_BIG5_HKSCS }, + { "gb18030", RTL_TEXTENCODING_GB_18030 }, + { "euc", RTL_TEXTENCODING_EUC_JP }, + { "iso8859-1", RTL_TEXTENCODING_ISO_8859_1 }, + { "iso8859-10", RTL_TEXTENCODING_ISO_8859_10 }, + { "iso8859-13", RTL_TEXTENCODING_ISO_8859_13 }, + { "iso8859-14", RTL_TEXTENCODING_ISO_8859_14 }, + { "iso8859-15", RTL_TEXTENCODING_ISO_8859_15 }, + { "iso8859-2", RTL_TEXTENCODING_ISO_8859_2 }, + { "iso8859-3", RTL_TEXTENCODING_ISO_8859_3 }, + { "iso8859-4", RTL_TEXTENCODING_ISO_8859_4 }, + { "iso8859-5", RTL_TEXTENCODING_ISO_8859_5 }, + { "iso8859-6", RTL_TEXTENCODING_ISO_8859_6 }, + { "iso8859-7", RTL_TEXTENCODING_ISO_8859_7 }, + { "iso8859-8", RTL_TEXTENCODING_ISO_8859_8 }, + { "iso8859-9", RTL_TEXTENCODING_ISO_8859_9 }, + { "koi8-r", RTL_TEXTENCODING_KOI8_R }, + { "koi8-u", RTL_TEXTENCODING_KOI8_U }, + { "pck", RTL_TEXTENCODING_MS_932 }, +#if (0) + { "sun_eu_greek", RTL_TEXTENCODING_DONTKNOW }, +#endif + { "utf-16", RTL_TEXTENCODING_UNICODE }, + { "utf-7", RTL_TEXTENCODING_UTF7 }, + { "utf-8", RTL_TEXTENCODING_UTF8 } +}; + +const _pair _iso_language_list[] = { + { "af", RTL_TEXTENCODING_ISO_8859_1 }, + { "ar", RTL_TEXTENCODING_ISO_8859_6 }, + { "az", RTL_TEXTENCODING_ISO_8859_9 }, + { "be", RTL_TEXTENCODING_ISO_8859_5 }, + { "bg", RTL_TEXTENCODING_ISO_8859_5 }, + { "ca", RTL_TEXTENCODING_ISO_8859_1 }, + { "cs", RTL_TEXTENCODING_ISO_8859_2 }, + { "da", RTL_TEXTENCODING_ISO_8859_1 }, + { "de", RTL_TEXTENCODING_ISO_8859_1 }, + { "el", RTL_TEXTENCODING_ISO_8859_7 }, + { "en", RTL_TEXTENCODING_ISO_8859_1 }, + { "es", RTL_TEXTENCODING_ISO_8859_1 }, + { "et", RTL_TEXTENCODING_ISO_8859_4 }, + { "eu", RTL_TEXTENCODING_ISO_8859_1 }, + { "fa", RTL_TEXTENCODING_ISO_8859_6 }, + { "fi", RTL_TEXTENCODING_ISO_8859_1 }, + { "fo", RTL_TEXTENCODING_ISO_8859_1 }, + { "fr", RTL_TEXTENCODING_ISO_8859_1 }, + { "gr", RTL_TEXTENCODING_ISO_8859_7 }, + { "he", RTL_TEXTENCODING_ISO_8859_8 }, + { "hi", RTL_TEXTENCODING_DONTKNOW }, + { "hr", RTL_TEXTENCODING_ISO_8859_2 }, + { "hu", RTL_TEXTENCODING_ISO_8859_2 }, + { "hy", RTL_TEXTENCODING_DONTKNOW }, + { "id", RTL_TEXTENCODING_ISO_8859_1 }, + { "is", RTL_TEXTENCODING_ISO_8859_1 }, + { "it", RTL_TEXTENCODING_ISO_8859_1 }, + { "iw", RTL_TEXTENCODING_ISO_8859_8 }, + { "ja", RTL_TEXTENCODING_EUC_JP }, + { "ka", RTL_TEXTENCODING_DONTKNOW }, + { "kk", RTL_TEXTENCODING_ISO_8859_5 }, + { "ko", RTL_TEXTENCODING_EUC_KR }, + { "lt", RTL_TEXTENCODING_ISO_8859_4 }, + { "lv", RTL_TEXTENCODING_ISO_8859_4 }, + { "mk", RTL_TEXTENCODING_ISO_8859_5 }, + { "mr", RTL_TEXTENCODING_DONTKNOW }, + { "ms", RTL_TEXTENCODING_ISO_8859_1 }, + { "nl", RTL_TEXTENCODING_ISO_8859_1 }, + { "no", RTL_TEXTENCODING_ISO_8859_1 }, + { "pl", RTL_TEXTENCODING_ISO_8859_2 }, + { "pt", RTL_TEXTENCODING_ISO_8859_1 }, + { "ro", RTL_TEXTENCODING_ISO_8859_2 }, + { "ru", RTL_TEXTENCODING_ISO_8859_5 }, + { "sa", RTL_TEXTENCODING_DONTKNOW }, + { "sk", RTL_TEXTENCODING_ISO_8859_2 }, + { "sl", RTL_TEXTENCODING_ISO_8859_2 }, + { "sq", RTL_TEXTENCODING_ISO_8859_2 }, + { "sv", RTL_TEXTENCODING_ISO_8859_1 }, + { "sw", RTL_TEXTENCODING_ISO_8859_1 }, + { "ta", RTL_TEXTENCODING_DONTKNOW }, + { "th", RTL_TEXTENCODING_DONTKNOW }, + { "tr", RTL_TEXTENCODING_ISO_8859_9 }, + { "tt", RTL_TEXTENCODING_ISO_8859_5 }, + { "uk", RTL_TEXTENCODING_ISO_8859_5 }, + { "ur", RTL_TEXTENCODING_ISO_8859_6 }, + { "uz", RTL_TEXTENCODING_ISO_8859_9 }, + { "vi", RTL_TEXTENCODING_DONTKNOW }, + { "zh", RTL_TEXTENCODING_BIG5 } +}; + +/***************************************************************************** + return the text encoding corresponding to the given locale + *****************************************************************************/ + +rtl_TextEncoding osl_getTextEncodingFromLocale( rtl_Locale * pLocale ) +{ + const _pair *language = 0; + char locale_buf[64] = ""; + char *cp; + + /* default to process locale if pLocale == NULL */ + if( NULL == pLocale ) + osl_getProcessLocale( &pLocale ); + + /* convert rtl_Locale to locale string */ + if( _compose_locale( pLocale, locale_buf, 64 ) ) + { + /* check special handling list (EUC) first */ + const unsigned int members = sizeof( _full_locale_list ) / sizeof( _pair ); + language = _pair_search( locale_buf, _full_locale_list, members); + + if( NULL == language ) + { + /* + * check if there is a charset qualifier at the end of the given locale string + * e.g. de.ISO8859-15 or de.ISO8859-15@euro which strongly indicates what + * charset to use + */ + cp = strrchr( locale_buf, '.' ); + + if( NULL != cp ) + { + const unsigned int members = sizeof( _locale_extension_list ) / sizeof( _pair ); + language = _pair_search( cp + 1, _locale_extension_list, members); + } + } + + /* use iso language code to determine the charset */ + if( NULL == language ) + { + const unsigned int members = sizeof( _iso_language_list ) / sizeof( _pair ); + + /* iso lang codes have 2 charaters */ + locale_buf[2] = '\0'; + + language = _pair_search( locale_buf, _iso_language_list, members); + } + } + + /* a matching item in our list provides a mapping from codeset to + * rtl-codeset */ + if ( language != NULL ) + return language->value; + + return RTL_TEXTENCODING_DONTKNOW; +} + +#ifdef MACOSX +#include "system.h" + +/* OS X locale discovery function */ +int (*pGetOSXLocale)( char *, sal_uInt32 ); + +oslModule SAL_CALL osl_psz_loadModule(const sal_Char *pszModuleName, sal_Int32 nRtldMode); +/***************************************************************************** + return the current process locale + *****************************************************************************/ + +int macosx_getLocale(char *locale, sal_uInt32 bufferLen); + +void _imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + static char *locale = NULL; + + /* basic thread safeness */ +// pthread_mutex_lock( &aLocalMutex ); + + /* Only fetch the locale once and cache it */ + if ( NULL == locale ) + { + + locale = (char *)malloc( 20 ); + if ( locale ) + macosx_getLocale( locale, 20 ); + else + fprintf( stderr, "nlsupport.c: locale allocation returned NULL!\n" ); + } + + /* handle the case where OS specific method of finding locale fails */ + if ( NULL == locale ) + { + /* simulate behavior of setlocale */ + locale = getenv( "LC_ALL" ); + + if( NULL == locale ) + locale = getenv( "LC_CTYPE" ); + + if( NULL == locale ) + locale = getenv( "LANG" ); + + if( NULL == locale ) + locale = "C"; + } + + /* return the locale */ + *ppLocale = _parse_locale( locale ); + + setenv( "LC_ALL", locale, 1); + setenv("LC_CTYPE", locale, 1 ); + setenv("LANG", locale, 1 ); + +#ifdef DEBUG + fprintf( stderr, "nlsupport.c: _imp_getProcessLocale() returning %s as current locale.\n", locale ); +#endif + +// pthread_mutex_unlock( &aLocalMutex ); + +} +#else +/***************************************************************************** + return the current process locale + *****************************************************************************/ + +void _imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + /* simulate behavior off setlocale */ + char * locale = getenv( "LC_ALL" ); + + if( NULL == locale ) + locale = getenv( "LC_CTYPE" ); + + if( NULL == locale ) + locale = getenv( "LANG" ); + + if( NULL == locale ) + locale = "C"; + + *ppLocale = _parse_locale( locale ); +} +#endif + +/***************************************************************************** + set the current process locale + *****************************************************************************/ + +int _imp_setProcessLocale( rtl_Locale * pLocale ) +{ + char locale_buf[64]; + + /* convert rtl_Locale to locale string */ + if( NULL != _compose_locale( pLocale, locale_buf, 64 ) ) + { + /* only change env vars that exist already */ + if( getenv( "LC_ALL" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) + setenv( "LC_ALL", locale_buf, 1); +#else + setenv( "LC_ALL", locale_buf ); +#endif + } + + if( getenv( "LC_CTYPE" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) + setenv("LC_CTYPE", locale_buf, 1 ); +#else + setenv( "LC_CTYPE", locale_buf ); +#endif + } + + if( getenv( "LANG" ) ) { +#if defined( FREEBSD ) || defined( NETBSD ) || defined( MACOSX ) + setenv("LC_CTYPE", locale_buf, 1 ); +#else + setenv( "LANG", locale_buf ); +#endif + } + } + + return 0; +} + +#endif /* ifdef LINUX || SOLARIS || MACOSX || NETBSD */ + + diff --git a/sal/osl/unx/osxlocale.cxx b/sal/osl/unx/osxlocale.cxx new file mode 100644 index 000000000000..9a20fd9ceb12 --- /dev/null +++ b/sal/osl/unx/osxlocale.cxx @@ -0,0 +1,129 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include <sal/types.h> +#include <assert.h> + +#include <premac.h> +#include <CoreServices/CoreServices.h> +#include <CoreFoundation/CoreFoundation.h> +#include <postmac.h> + +namespace /* private */ +{ + template <typename T> + class CFGuard + { + public: + explicit CFGuard(T& rT) : rT_(rT) {} + ~CFGuard() { if (rT_) CFRelease(rT_); } + private: + T& rT_; + }; + + typedef CFGuard<CFArrayRef> CFArrayGuard; + typedef CFGuard<CFStringRef> CFStringGuard; + typedef CFGuard<CFPropertyListRef> CFPropertyListGuard; + + /** Get the current process locale from system + */ + CFStringRef getProcessLocale() + { + CFPropertyListRef pref = CFPreferencesCopyAppValue(CFSTR("AppleLocale"), kCFPreferencesCurrentApplication); + CFPropertyListGuard proplGuard(pref); + + if (pref == NULL) // return fallback value 'en_US' + return CFStringCreateWithCString(kCFAllocatorDefault, "en_US", kCFStringEncodingASCII); + + CFStringRef sref = (CFGetTypeID(pref) == CFArrayGetTypeID()) ? (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)pref, 0) : (CFStringRef)pref; + + // NOTE: this API is only available with Mac OS X >=10.3. We need to use it because + // Apple used non-ISO values on systems <10.2 like "German" for instance but didn't + // upgrade those values during upgrade to newer Mac OS X versions. See also #i54337# + return CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, sref); + } +} // namespace private + +/** Grab current locale from system. +*/ +extern "C" { +int macosx_getLocale(char *locale, sal_uInt32 bufferLen) +{ + CFStringRef sref = getProcessLocale(); + CFStringGuard sGuard(sref); + + assert(sref != NULL && "osxlocale.cxx: getProcessLocale must return a non-NULL value"); + + // split the string into substrings; the first two (if there are two) substrings + // are language and country + CFArrayRef subs = CFStringCreateArrayBySeparatingStrings(NULL, sref, CFSTR("_")); + CFArrayGuard arrGuard(subs); + + CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(subs, 0); + CFStringGetCString(lang, locale, bufferLen, kCFStringEncodingASCII); + + // country also available? Assumption: if the array contains more than one + // value the second value is always the country! + if (CFArrayGetCount(subs) > 1) + { + strlcat(locale, "_", bufferLen - strlen(locale)); + + CFStringRef country = (CFStringRef)CFArrayGetValueAtIndex(subs, 1); + CFStringGetCString(country, locale + strlen(locale), bufferLen - strlen(locale), kCFStringEncodingASCII); + } + // Append 'UTF-8' to the locale because the Mac OS X file + // system interface is UTF-8 based and sal tries to determine + // the file system locale from the locale information + strlcat(locale, ".UTF-8", bufferLen - strlen(locale)); + + return noErr; +} +} + + + +/* + * macxp_OSXConvertCFEncodingToIANACharSetName + * + * Convert a CoreFoundation text encoding to an IANA charset name. + */ +extern "C" int macxp_OSXConvertCFEncodingToIANACharSetName( char *buffer, unsigned int bufferLen, CFStringEncoding cfEncoding ) +{ + CFStringRef sCFEncodingName; + + sCFEncodingName = CFStringConvertEncodingToIANACharSetName( cfEncoding ); + CFStringGetCString( sCFEncodingName, buffer, bufferLen, cfEncoding ); + + if ( sCFEncodingName ) + CFRelease( sCFEncodingName ); + + return( noErr ); +} + diff --git a/sal/osl/unx/pipe.c b/sal/osl/unx/pipe.c new file mode 100644 index 000000000000..ede4cd7e074f --- /dev/null +++ b/sal/osl/unx/pipe.c @@ -0,0 +1,592 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/pipe.h> +#include <osl/diagnose.h> +/*#include <osl/signal.h>*/ +#include <osl/thread.h> +#include <osl/interlck.h> + +#include "sockimpl.h" + +#define PIPEDEFAULTPATH "/tmp" +#define PIPEALTERNATEPATH "/var/tmp" + +#define PIPENAMEMASK "OSL_PIPE_%s" +#define SECPIPENAMEMASK "OSL_PIPE_%s_%s" + +sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax); +oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, oslSecurity Security); + +/*#define DEBUG_OSL_PIPE*/ +/*#define TRACE_OSL_PIPE*/ + + +/*****************************************************************************/ +/* enum oslPipeError */ +/*****************************************************************************/ + +static struct +{ + int errcode; + oslPipeError error; +} PipeError[]= { + { 0, osl_Pipe_E_None }, /* no error */ + { EPROTOTYPE, osl_Pipe_E_NoProtocol }, /* Protocol wrong type for socket */ + { ENOPROTOOPT, osl_Pipe_E_NoProtocol }, /* Protocol not available */ + { EPROTONOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol not supported */ + { ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Socket type not supported */ + { EPFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol family not supported */ + { EAFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Address family not supported by */ + /* protocol family */ + { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */ + /* of reset */ + { ECONNABORTED, osl_Pipe_E_ConnectionAbort }, /* Software caused connection abort */ + { ECONNRESET, osl_Pipe_E_ConnectionReset }, /* Connection reset by peer */ + { ENOBUFS, osl_Pipe_E_NoBufferSpace }, /* No buffer space available */ + { ETIMEDOUT, osl_Pipe_E_TimedOut }, /* Connection timed out */ + { ECONNREFUSED, osl_Pipe_E_ConnectionRefused }, /* Connection refused */ + { -1, osl_Pipe_E_invalidError } +}; + + +/* map */ +/* mfe: NOT USED + static int osl_NativeFromPipeError(oslPipeError errorCode) + { + int i = 0; + + while ((PipeError[i].error != osl_Pipe_E_invalidError) && + (PipeError[i].error != errorCode)) i++; + + return PipeError[i].errcode; + + } +*/ + +/* reverse map */ +static oslPipeError osl_PipeErrorFromNative(int nativeType) +{ + int i = 0; + + while ((PipeError[i].error != osl_Pipe_E_invalidError) && + (PipeError[i].errcode != nativeType)) i++; + + return PipeError[i].error; +} + + +/* macros */ +#define ERROR_TO_NATIVE(x) osl_NativeFromPipeError(x) +#define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y) + + +/*****************************************************************************/ +/* osl_create/destroy-PipeImpl */ +/*****************************************************************************/ + +oslPipe __osl_createPipeImpl() +{ + oslPipe pPipeImpl; + + pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl)); + pPipeImpl->m_nRefCount =1; + pPipeImpl->m_bClosed = sal_False; +#if defined(LINUX) + pPipeImpl->m_bIsInShutdown = sal_False; + pPipeImpl->m_bIsAccepting = sal_False; +#endif + return pPipeImpl; +} + +void __osl_destroyPipeImpl(oslPipe pImpl) +{ + if (pImpl != NULL) + free(pImpl); +} + + +/*****************************************************************************/ +/* osl_createPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security) +{ + oslPipe pPipe=0; + rtl_String* strPipeName=0; + sal_Char* pszPipeName=0; + + if ( ustrPipeName != 0 ) + { + rtl_uString2String( &strPipeName, + rtl_uString_getStr(ustrPipeName), + rtl_uString_getLength(ustrPipeName), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszPipeName = rtl_string_getStr(strPipeName); + pPipe = osl_psz_createPipe(pszPipeName, Options, Security); + + if ( strPipeName != 0 ) + { + rtl_string_release(strPipeName); + } + } + + return pPipe; + +} + +oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, + oslSecurity Security) +{ + int Flags; + size_t len; + struct sockaddr_un addr; + + sal_Char name[PATH_MAX + 1]; + oslPipe pPipe; + + if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0) + { + strncpy(name, PIPEDEFAULTPATH, sizeof(name)); + } + else + { + strncpy(name, PIPEALTERNATEPATH, sizeof(name)); + } + + + strncat(name, "/", sizeof(name)); + + if (Security) + { + sal_Char Ident[256]; + + Ident[0] = '\0'; + + OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident))); + + snprintf(&name[strlen(name)], sizeof(name), SECPIPENAMEMASK, Ident, pszPipeName); + } + else + { + snprintf(&name[strlen(name)], sizeof(name), PIPENAMEMASK, pszPipeName); + } + + + /* alloc memory */ + pPipe= __osl_createPipeImpl(); + + /* create socket */ + pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0); + if ( pPipe->m_Socket < 0 ) + { + OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s\n",errno, strerror(errno)); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + +/* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/ + + /* set close-on-exec flag */ + if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1) + { + OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s\n",errno,strerror(errno)); + } + } + + memset(&addr, 0, sizeof(addr)); + + OSL_TRACE("osl_createPipe : Pipe Name '%s'",name); + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, name, sizeof(addr.sun_path)); +#if defined(FREEBSD) + len = SUN_LEN(&addr); +#else + len = sizeof(addr); +#endif + + if ( Options & osl_Pipe_CREATE ) + { + struct stat status; + + /* check if there exists an orphan filesystem entry */ + if ( ( stat(name, &status) == 0) && + ( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) ) + { + if ( connect(pPipe->m_Socket,(struct sockaddr *)&addr,len) >= 0 ) + { + OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s\n",errno,strerror(errno)); + close (pPipe->m_Socket); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + + unlink(name); + } + + /* ok, fs clean */ + if ( bind(pPipe->m_Socket, (struct sockaddr *)&addr, len) < 0 ) + { + OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s\n",errno,strerror(errno)); + close (pPipe->m_Socket); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + + /* Only give access to all if no security handle was specified, otherwise security + depends on umask */ + + if ( !Security ) + chmod(name,S_IRWXU | S_IRWXG |S_IRWXO); + + + strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name)); + + if ( listen(pPipe->m_Socket, 5) < 0 ) + { + OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s\n",errno,strerror(errno)); + unlink(name); /* remove filesystem entry */ + close (pPipe->m_Socket); + __osl_destroyPipeImpl(pPipe); + return NULL; + } + + return (pPipe); + } + else + { /* osl_pipe_OPEN */ + if ( access(name, F_OK) != -1 ) + { + if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 ) + { + return (pPipe); + } + + OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s\n",errno,strerror(errno)); + } + + close (pPipe->m_Socket); + __osl_destroyPipeImpl(pPipe); + return NULL; + } +} + +void SAL_CALL osl_acquirePipe( oslPipe pPipe ) +{ + osl_incrementInterlockedCount( &(pPipe->m_nRefCount) ); +} + +void SAL_CALL osl_releasePipe( oslPipe pPipe ) +{ + + if( 0 == pPipe ) + return; + + if( 0 == osl_decrementInterlockedCount( &(pPipe->m_nRefCount) ) ) + { + if( ! pPipe->m_bClosed ) + osl_closePipe( pPipe ); + + __osl_destroyPipeImpl( pPipe ); + } +} + +void SAL_CALL osl_closePipe( oslPipe pPipe ) +{ + int nRet; +#if defined(LINUX) + size_t len; + struct sockaddr_un addr; + int fd; +#endif + int ConnFD; + + if( ! pPipe ) + { + return; + } + + if( pPipe->m_bClosed ) + { + return; + } + + ConnFD = pPipe->m_Socket; + + /* + Thread does not return from accept on linux, so + connect to the accepting pipe + */ +#if defined(LINUX) + if ( pPipe->m_bIsAccepting ) + { + pPipe->m_bIsInShutdown = sal_True; + pPipe->m_Socket = -1; + fd = socket(AF_UNIX, SOCK_STREAM, 0); + memset(&addr, 0, sizeof(addr)); + + OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe->m_Name); + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, pPipe->m_Name, sizeof(addr.sun_path)); + len = sizeof(addr); + + nRet = connect( fd, (struct sockaddr *)&addr, len); +#if OSL_DEBUG_LEVEL > 1 + if ( nRet < 0 ) + { + perror("connect in osl_destroyPipe"); + } +#endif /* OSL_DEBUG_LEVEL */ + close(fd); + } +#endif /* LINUX */ + + + nRet = shutdown(ConnFD, 2); + if ( nRet < 0 ) + { + OSL_TRACE("shutdown in destroyPipe failed : '%s'\n",strerror(errno)); + } + + nRet = close(ConnFD); + if ( nRet < 0 ) + { + OSL_TRACE("close in destroyPipe failed : '%s'\n",strerror(errno)); + } + /* remove filesystem entry */ + if ( strlen(pPipe->m_Name) > 0 ) + { + unlink(pPipe->m_Name); + } + pPipe->m_bClosed = sal_True; + +/* OSL_TRACE("Out osl_destroyPipe"); */ +} + + +/*****************************************************************************/ +/* osl_acceptPipe */ +/*****************************************************************************/ +oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe) +{ + int s, flags; + oslPipe pAcceptedPipe; + + OSL_ASSERT(pPipe); + if ( pPipe == 0 ) + { + return NULL; + } + + OSL_ASSERT(strlen(pPipe->m_Name) > 0); + +#if defined(LINUX) + pPipe->m_bIsAccepting = sal_True; +#endif + + s = accept(pPipe->m_Socket, NULL, NULL); + +#if defined(LINUX) + pPipe->m_bIsAccepting = sal_False; +#endif + + if (s < 0) + { + OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno)); + return NULL; + } + +#if defined(LINUX) + if ( pPipe->m_bIsInShutdown ) + { + close(s); + return NULL; + } +#endif /* LINUX */ + else + { + /* alloc memory */ + pAcceptedPipe= __osl_createPipeImpl(); + + OSL_ASSERT(pAcceptedPipe); + if(pAcceptedPipe==NULL) + { + close(s); + return NULL; + } + + /* set close-on-exec flag */ + if (!((flags = fcntl(s, F_GETFD, 0)) < 0)) + { + flags |= FD_CLOEXEC; + if (fcntl(s, F_SETFD, flags) < 0) + { + OSL_TRACE("osl_acceptPipe: error changing socket flags. " + "Errno: %d; %s",errno,strerror(errno)); + } + } + + pAcceptedPipe->m_Socket = s; + } + + return pAcceptedPipe; +} + +/*****************************************************************************/ +/* osl_receivePipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe, + void* pBuffer, + sal_Int32 BytesToRead) +{ + int nRet = 0; + + OSL_ASSERT(pPipe); + + if ( pPipe == 0 ) + { + OSL_TRACE("osl_receivePipe : Invalid socket"); + errno=EINVAL; + return -1; + } + + nRet = recv(pPipe->m_Socket, + (sal_Char*)pBuffer, + BytesToRead, 0); + + if ( nRet <= 0 ) + { + OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno)); + } + + return nRet; +} + + +/*****************************************************************************/ +/* osl_sendPipe */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe, + const void* pBuffer, + sal_Int32 BytesToSend) +{ + int nRet=0; + + OSL_ASSERT(pPipe); + + if ( pPipe == 0 ) + { + OSL_TRACE("osl_sendPipe : Invalid socket"); + errno=EINVAL; + return -1; + } + + nRet = send(pPipe->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, 0); + + + if ( nRet <= 0 ) + { + OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno)); + } + + return nRet; +} + + +/*****************************************************************************/ +/* osl_getLastPipeError */ +/*****************************************************************************/ +oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe) +{ + (void) pPipe; /* unused */ + return ERROR_FROM_NATIVE(errno); +} + + +sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n ) +{ + /* loop until all desired bytes were send or an error occured */ + sal_Int32 BytesSend= 0; + sal_Int32 BytesToSend= n; + + OSL_ASSERT(pPipe); + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToSend -= RetVal; + BytesSend += RetVal; + pBuffer= (sal_Char*)pBuffer + RetVal; + } + + return BytesSend; +} + +sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n ) +{ + /* loop until all desired bytes were read or an error occured */ + sal_Int32 BytesRead= 0; + sal_Int32 BytesToRead= n; + + OSL_ASSERT( pPipe ); + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToRead -= RetVal; + BytesRead += RetVal; + pBuffer= (sal_Char*)pBuffer + RetVal; + } + return BytesRead; +} + + diff --git a/sal/osl/unx/process.c b/sal/osl/unx/process.c new file mode 100644 index 000000000000..300a1446e81a --- /dev/null +++ b/sal/osl/unx/process.c @@ -0,0 +1,1536 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/* + * ToDo: + * - cleanup of process status things + * - cleanup of process spawning + * - cleanup of resource transfer + */ + +#if defined(SOLARIS) + // The procfs may only be used without LFS in 32bits. +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + + +#ifdef FREEBSD +#include <machine/param.h> +#endif + +#include "system.h" +#if defined(SOLARIS) +# include <sys/procfs.h> +#endif +#include <osl/diagnose.h> +#include <osl/mutex.h> + +#ifndef _OSL_CONDITN_H_ +#include <osl/conditn.h> +#endif +#include <osl/thread.h> +#include <osl/file.h> +#include <osl/signal.h> +#include <rtl/alloc.h> + +#include <grp.h> + +#include "procimpl.h" +#include "sockimpl.h" +#include "secimpl.h" + + +#define MAX_ARGS 255 +#define MAX_ENVS 255 + +#if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD) +#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) +#endif + +/* implemented in file.c */ +extern oslFileError FileURLToPath( char *, size_t, rtl_uString* ); +extern oslFileHandle osl_createFileHandleFromFD( int fd ); + +/****************************************************************************** + * + * Data Type Definition + * + ******************************************************************************/ + +typedef struct { + int m_hPipe; + int m_hConn; + sal_Char m_Name[PATH_MAX + 1]; +} Pipe; + +typedef struct { + const sal_Char* m_pszArgs[MAX_ARGS + 1]; + oslProcessOption m_options; + const sal_Char* m_pszDir; + sal_Char* m_pszEnv[MAX_ENVS + 1]; + uid_t m_uid; + gid_t m_gid; + sal_Char* m_name; + oslCondition m_started; + oslProcessImpl* m_pProcImpl; + oslFileHandle *m_pInputWrite; + oslFileHandle *m_pOutputRead; + oslFileHandle *m_pErrorRead; +} ProcessData; + +typedef struct _oslPipeImpl { + int m_Socket; + sal_Char m_Name[PATH_MAX + 1]; +} oslPipeImpl; + + +/****************************************************************************** + * + * Function Declarations + * + *****************************************************************************/ + +oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, + sal_Char *pszArguments[], + oslProcessOption Options, + oslSecurity Security, + sal_Char *pszDirectory, + sal_Char *pszEnvironments[], + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead ); + + +oslProcessError SAL_CALL osl_searchPath_impl( + const sal_Char* pszName, + const sal_Char* pszPath, + sal_Char Separator, + sal_Char *pszBuffer, + sal_uInt32 Max); + + +sal_Bool osl_getFullPath(const sal_Char* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen); + +static oslProcessImpl* ChildList; +static oslMutex ChildListMutex; + +/****************************************************************************** + Deprecated + Old and buggy implementation of osl_searchPath used only by + osl_psz_executeProcess. + A new implemenation is in file_path_helper.cxx + *****************************************************************************/ + +oslProcessError SAL_CALL osl_searchPath_impl(const sal_Char* pszName, const sal_Char* pszPath, + sal_Char Separator, sal_Char *pszBuffer, sal_uInt32 Max) +{ + sal_Char path[PATH_MAX + 1]; + sal_Char *pchr; + + path[0] = '\0'; + + OSL_ASSERT(pszName != NULL); + + if ( pszName == 0 ) + { + return osl_Process_E_NotFound; + } + + if (pszPath == NULL) + pszPath = "PATH"; + + if (Separator == '\0') + Separator = ':'; + + + if ( (pchr = getenv(pszPath)) != 0 ) + { + sal_Char *pstr; + + while (*pchr != '\0') + { + pstr = path; + + while ((*pchr != '\0') && (*pchr != Separator)) + *pstr++ = *pchr++; + + if ((pstr > path) && ((*(pstr - 1) != '/'))) + *pstr++ = '/'; + + *pstr = '\0'; + + strcat(path, pszName); + + if (access(path, 0) == 0) + { + char szRealPathBuf[PATH_MAX] = ""; + + if( NULL == realpath(path, szRealPathBuf) || (strlen(szRealPathBuf) >= (sal_uInt32)Max)) + return osl_Process_E_Unknown; + + strcpy(pszBuffer, path); + + return osl_Process_E_None; + } + + if (*pchr == Separator) + pchr++; + } + } + + return osl_Process_E_NotFound; +} + +/****************************************************************************** + * + * New io resource transfer functions + * + *****************************************************************************/ + + +/********************************************** + sendFdPipe + *********************************************/ + +static sal_Bool sendFdPipe(int PipeFD, int SocketFD) +{ + sal_Bool bRet = sal_False; + + struct iovec iov[1]; + struct msghdr msg; + char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ + int nSend; + int RetCode=0; + +#if defined(IOCHANNEL_TRANSFER_BSD) + + OSL_TRACE("IOCHANNEL_TRANSFER_BSD send"); +/* OSL_TRACE("sending fd %i\n",SocketFD); */ + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + + msg.msg_accrights = (caddr_t) &SocketFD; /* addr of descriptor */ + msg.msg_accrightslen = sizeof(int); /* pass 1 descriptor */ + buf[1] = 0; /* zero status means OK */ + buf[0] = 0; /* null byte flag to recv_fd() */ + +#else + + struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN); + + OSL_TRACE("!!!!!! IOCHANNEL_TRANSFER_BSD_RENO send"); +/* OSL_TRACE("sending fd %i\n",SocketFD); */ + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = (caddr_t) cmptr; + msg.msg_controllen = CONTROLLEN; + + cmptr->cmsg_level = SOL_SOCKET; + cmptr->cmsg_type = SCM_RIGHTS; + cmptr->cmsg_len = CONTROLLEN; + memcpy(CMSG_DATA(cmptr), &SocketFD, sizeof(int)); + +#endif + + if ( ( nSend = sendmsg(PipeFD, &msg, 0) ) > 0 ) + { + bRet = sal_True; + OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend); + + } + else + { + OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); + } + + nSend=read(PipeFD,&RetCode,sizeof(RetCode)); + + if ( nSend > 0 && RetCode == 1 ) + { + OSL_TRACE("sendFdPipe : resource was received\n"); + } + else + { + OSL_TRACE("sendFdPipe : resource wasn't received\n"); + } + +#if defined(IOCHANNEL_TRANSFER_BSD_RENO) + free(cmptr); +#endif + + return bRet; +} + +/********************************************** + receiveFdPipe + *********************************************/ + +static oslSocket receiveFdPipe(int PipeFD) +{ + oslSocket pSocket = 0; + struct msghdr msghdr; + struct iovec iov[1]; + char buffer[2]; + sal_Int32 nRead; + int newfd=-1; + int nRetCode=0; +/* char *ptr; */ + +#if defined(IOCHANNEL_TRANSFER_BSD) + + OSL_TRACE("IOCHANNEL_TRANSFER_BSD receive\n"); + + iov[0].iov_base = buffer; + iov[0].iov_len = sizeof(buffer); + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = iov; + msghdr.msg_iovlen = 1; + msghdr.msg_accrights = (caddr_t) &newfd; /* addr of descriptor */ + msghdr.msg_accrightslen = sizeof(int); /* receive 1 descriptor */ + +#else + struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN); + + OSL_TRACE(" !!!! IOCHANNEL_TRANSFER_BSD_RENO receive"); + + iov[0].iov_base = buffer; + iov[0].iov_len = sizeof(buffer); + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = iov; + msghdr.msg_iovlen = 1; + + msghdr.msg_control = (caddr_t) cmptr; + msghdr.msg_controllen = CONTROLLEN; + +#endif + + +#if defined(IOCHANNEL_TRANSFER_BSD) + + if ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) + { + OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead); + } +#else + + if ( ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) && + ( msghdr.msg_controllen == CONTROLLEN ) ) + { + OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead); + memcpy(&newfd, CMSG_DATA(cmptr), sizeof(int)); + } +#endif + else + { + OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno)); + } + + if ( newfd >= 0 ) + { + pSocket = __osl_createSocketImpl(newfd); + nRetCode=1; + OSL_TRACE("received fd %i\n",newfd); + } + + OSL_TRACE("receiveFdPipe : writing back %i",nRetCode); + nRead=write(PipeFD,&nRetCode,sizeof(nRetCode)); + +#if defined(IOCHANNEL_TRANSFER_BSD_RENO) + free(cmptr); +#endif + + return pSocket; +} + +/********************************************** + osl_sendResourcePipe + *********************************************/ + +sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket) +{ + sal_Bool bRet = sal_False; + + if ( pSocket == 0 || pPipe == 0 ) + { + return sal_False; + } + + bRet = sendFdPipe(pPipe->m_Socket,pSocket->m_Socket); + + return bRet; +} + +/********************************************** + osl_receiveResourcePipe + *********************************************/ + +oslSocket osl_receiveResourcePipe(oslPipe pPipe) +{ + oslSocket pSocket=0; + + if ( pPipe == 0 ) + { + return 0; + } + + pSocket = receiveFdPipe(pPipe->m_Socket); + + return (oslSocket) pSocket; +} + + + +/****************************************************************************** + * + * Functions for starting a process + * + *****************************************************************************/ + +static void ChildStatusProc(void *pData) +{ + pid_t pid = -1; + int status = 0; + int channel[2]; + ProcessData data; + ProcessData *pdata; + int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 }; + + pdata = (ProcessData *)pData; + + /* make a copy of our data, because forking will only copy + our local stack of the thread, so the process data will not be accessible + in our child process */ + memcpy(&data, pData, sizeof(data)); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1) + status = errno; + + fcntl(channel[0], F_SETFD, FD_CLOEXEC); + fcntl(channel[1], F_SETFD, FD_CLOEXEC); + + /* Create redirected IO pipes */ + if ( status == 0 && data.m_pInputWrite ) + if (pipe( stdInput ) == -1) + status = errno; + + if ( status == 0 && data.m_pOutputRead ) + if (pipe( stdOutput ) == -1) + status = errno; + + if ( status == 0 && data.m_pErrorRead ) + if (pipe( stdError ) == -1) + status = errno; + + if ( (status == 0) && ((pid = fork()) == 0) ) + { + /* Child */ + int chstatus = 0; + sal_Int32 nWrote; + + if (channel[0] != -1) close(channel[0]); + + if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid()))) + { + OSL_ASSERT(geteuid() == 0); /* must be root */ + + if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0)) + OSL_TRACE("Failed to change uid and guid, errno=%d (%s)\n", errno, strerror(errno)); +#if defined(LINUX) || defined (FREEBSD) + unsetenv("HOME"); +#else + putenv("HOME="); +#endif + } + + if (data.m_pszDir) + chstatus = chdir(data.m_pszDir); + + if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid())))) + { + int i; + for (i = 0; data.m_pszEnv[i] != NULL; i++) + { + if (strchr(data.m_pszEnv[i], '=') == NULL) + { + unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/ + } + else + { + putenv(data.m_pszEnv[i]); /*TODO: check error return*/ + } + } + + OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]); + + /* Connect std IO to pipe ends */ + + /* Write end of stdInput not used in child process */ + if (stdInput[1] != -1) close( stdInput[1] ); + + /* Read end of stdOutput not used in child process */ + if (stdOutput[0] != -1) close( stdOutput[0] ); + + /* Read end of stdError not used in child process */ + if (stdError[0] != -1) close( stdError[0] ); + + /* Redirect pipe ends to std IO */ + + if ( stdInput[0] != STDIN_FILENO ) + { + dup2( stdInput[0], STDIN_FILENO ); + if (stdInput[0] != -1) close( stdInput[0] ); + } + + if ( stdOutput[1] != STDOUT_FILENO ) + { + dup2( stdOutput[1], STDOUT_FILENO ); + if (stdOutput[1] != -1) close( stdOutput[1] ); + } + + if ( stdError[1] != STDERR_FILENO ) + { + dup2( stdError[1], STDERR_FILENO ); + if (stdError[1] != -1) close( stdError[1] ); + } + + pid=execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs); + + } + + OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno, strerror(errno)); + + OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); + + /* if we reach here, something went wrong */ + nWrote = write(channel[1], &errno, sizeof(errno)); + if (nWrote != sizeof(errno)) + OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); + + if (channel[1] != -1) close(channel[1]); + + _exit(255); + } + else + { /* Parent */ + int i = -1; + if (channel[1] != -1) close(channel[1]); + + /* Close unused pipe ends */ + if (stdInput[0] != -1) close( stdInput[0] ); + if (stdOutput[1] != -1) close( stdOutput[1] ); + if (stdError[1] != -1) close( stdError[1] ); + + if (pid > 0) + { + while (((i = read(channel[0], &status, sizeof(status))) < 0)) + { + if (errno != EINTR) + break; + } + } + + if (channel[0] != -1) close(channel[0]); + + if ((pid > 0) && (i == 0)) + { + pid_t child_pid; + osl_acquireMutex(ChildListMutex); + + pdata->m_pProcImpl->m_pid = pid; + pdata->m_pProcImpl->m_pnext = ChildList; + ChildList = pdata->m_pProcImpl; + + /* Store used pipe ends in data structure */ + + if ( pdata->m_pInputWrite ) + *(pdata->m_pInputWrite) = osl_createFileHandleFromFD( stdInput[1] ); + + if ( pdata->m_pOutputRead ) + *(pdata->m_pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] ); + + if ( pdata->m_pErrorRead ) + *(pdata->m_pErrorRead) = osl_createFileHandleFromFD( stdError[0] ); + + osl_releaseMutex(ChildListMutex); + + osl_setCondition(pdata->m_started); + + do + { + child_pid = waitpid(pid, &status, 0); + } while ( 0 > child_pid && EINTR == errno ); + + if ( child_pid < 0) + { + OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno, strerror(errno)); + + /* + We got an other error than EINTR. Anyway we have to wake up the + waiting thread under any circumstances */ + + child_pid = pid; + } + + + if ( child_pid > 0 ) + { + oslProcessImpl* pChild; + + osl_acquireMutex(ChildListMutex); + + pChild = ChildList; + + /* check if it is one of our child processes */ + while (pChild != NULL) + { + if (pChild->m_pid == child_pid) + { + if (WIFEXITED(status)) + pChild->m_status = WEXITSTATUS(status); + else + pChild->m_status = -1; + + osl_setCondition(pChild->m_terminated); + } + + pChild = pChild->m_pnext; + } + + osl_releaseMutex(ChildListMutex); + } + } + else + { + OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); + OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)\n", status, strerror(status)); + + /* Close pipe ends */ + if ( pdata->m_pInputWrite ) + *pdata->m_pInputWrite = NULL; + + if ( pdata->m_pOutputRead ) + *pdata->m_pOutputRead = NULL; + + if ( pdata->m_pErrorRead ) + *pdata->m_pErrorRead = NULL; + + if (stdInput[1] != -1) close( stdInput[1] ); + if (stdOutput[0] != -1) close( stdOutput[0] ); + if (stdError[0] != -1) close( stdError[0] ); + + //if pid > 0 then a process was created, even if it later failed + //e.g. bash searching for a command to execute, and we still + //need to clean it up to avoid "defunct" processes + if (pid > 0) + { + pid_t child_pid; + do + { + child_pid = waitpid(pid, &status, 0); + } while ( 0 > child_pid && EINTR == errno ); + } + + /* notify (and unblock) parent thread */ + osl_setCondition(pdata->m_started); + } + } +} + +/********************************************** + osl_executeProcess_WithRedirectedIO + *********************************************/ + +oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO( + rtl_uString *ustrImageName, + rtl_uString *ustrArguments[], + sal_uInt32 nArguments, + oslProcessOption Options, + oslSecurity Security, + rtl_uString *ustrWorkDir, + rtl_uString *ustrEnvironment[], + sal_uInt32 nEnvironmentVars, + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead + ) +{ + + oslProcessError Error; + sal_Char* pszWorkDir=0; + sal_Char** pArguments=0; + sal_Char** pEnvironment=0; + unsigned int idx; + + char szImagePath[PATH_MAX] = ""; + char szWorkDir[PATH_MAX] = ""; + + if ( ustrImageName && ustrImageName->length ) + { + FileURLToPath( szImagePath, PATH_MAX, ustrImageName ); + } + + if ( ustrWorkDir != 0 && ustrWorkDir->length ) + { + FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir ); + pszWorkDir = szWorkDir; + } + + if ( pArguments == 0 && nArguments > 0 ) + { + pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) ); + } + + + for ( idx = 0 ; idx < nArguments ; ++idx ) + { + rtl_String* strArg =0; + + + rtl_uString2String( &strArg, + rtl_uString_getStr(ustrArguments[idx]), + rtl_uString_getLength(ustrArguments[idx]), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + + pArguments[idx]=strdup(rtl_string_getStr(strArg)); + rtl_string_release(strArg); + pArguments[idx+1]=0; + } + + for ( idx = 0 ; idx < nEnvironmentVars ; ++idx ) + { + rtl_String* strEnv=0; + + if ( pEnvironment == 0 ) + { + pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) ); + } + + rtl_uString2String( &strEnv, + rtl_uString_getStr(ustrEnvironment[idx]), + rtl_uString_getLength(ustrEnvironment[idx]), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS ); + + pEnvironment[idx]=strdup(rtl_string_getStr(strEnv)); + rtl_string_release(strEnv); + pEnvironment[idx+1]=0; + } + + + Error = osl_psz_executeProcess(szImagePath, + pArguments, + Options, + Security, + pszWorkDir, + pEnvironment, + pProcess, + pInputWrite, + pOutputRead, + pErrorRead + ); + + if ( pArguments != 0 ) + { + for ( idx = 0 ; idx < nArguments ; ++idx ) + { + if ( pArguments[idx] != 0 ) + { + free(pArguments[idx]); + } + } + free(pArguments); + } + + if ( pEnvironment != 0 ) + { + for ( idx = 0 ; idx < nEnvironmentVars ; ++idx ) + { + if ( pEnvironment[idx] != 0 ) + { + free(pEnvironment[idx]); + } + } + free(pEnvironment); + } + + return Error; +} + +/********************************************** + osl_executeProcess + *********************************************/ + +oslProcessError SAL_CALL osl_executeProcess( + rtl_uString *ustrImageName, + rtl_uString *ustrArguments[], + sal_uInt32 nArguments, + oslProcessOption Options, + oslSecurity Security, + rtl_uString *ustrWorkDir, + rtl_uString *ustrEnvironment[], + sal_uInt32 nEnvironmentVars, + oslProcess *pProcess + ) +{ + return osl_executeProcess_WithRedirectedIO( + ustrImageName, + ustrArguments, + nArguments, + Options, + Security, + ustrWorkDir, + ustrEnvironment, + nEnvironmentVars, + pProcess, + NULL, + NULL, + NULL + ); +} + +/********************************************** + osl_psz_executeProcess + *********************************************/ + +oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, + sal_Char *pszArguments[], + oslProcessOption Options, + oslSecurity Security, + sal_Char *pszDirectory, + sal_Char *pszEnvironments[], + oslProcess *pProcess, + oslFileHandle *pInputWrite, + oslFileHandle *pOutputRead, + oslFileHandle *pErrorRead + ) +{ + int i; + sal_Char path[PATH_MAX + 1]; + ProcessData Data; + oslThread hThread; + + path[0] = '\0'; + + memset(&Data,0,sizeof(ProcessData)); + Data.m_pInputWrite = pInputWrite; + Data.m_pOutputRead = pOutputRead; + Data.m_pErrorRead = pErrorRead; + + if (pszImageName == NULL) + pszImageName = pszArguments[0]; + + OSL_ASSERT(pszImageName != NULL); + + if ( pszImageName == 0 ) + { + return osl_Process_E_NotFound; + } + + if ((Options & osl_Process_SEARCHPATH) && + (osl_searchPath_impl(pszImageName, NULL, '\0', path, sizeof(path)) == osl_Process_E_None)) + pszImageName = path; + + Data.m_pszArgs[0] = strdup(pszImageName); + Data.m_pszArgs[1] = 0; + + if ( pszArguments != 0 ) + { + for (i = 0; ((i + 2) < MAX_ARGS) && (pszArguments[i] != NULL); i++) + Data.m_pszArgs[i+1] = strdup(pszArguments[i]); + Data.m_pszArgs[i+2] = NULL; + } + + Data.m_options = Options; + Data.m_pszDir = (pszDirectory != NULL) ? strdup(pszDirectory) : NULL; + + if (pszEnvironments != NULL) + { + for (i = 0; ((i + 1) < MAX_ENVS) && (pszEnvironments[i] != NULL); i++) + Data.m_pszEnv[i] = strdup(pszEnvironments[i]); + Data.m_pszEnv[i+1] = NULL; + } + else + Data.m_pszEnv[0] = NULL; + + if (Security != NULL) + { + Data.m_uid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_uid; + Data.m_gid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_gid; + Data.m_name = ((oslSecurityImpl*)Security)->m_pPasswd.pw_name; + } + else + Data.m_uid = (uid_t)-1; + + Data.m_pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); + Data.m_pProcImpl->m_pid = 0; + Data.m_pProcImpl->m_terminated = osl_createCondition(); + Data.m_pProcImpl->m_pnext = NULL; + + if (ChildListMutex == NULL) + ChildListMutex = osl_createMutex(); + + Data.m_started = osl_createCondition(); + + hThread = osl_createThread(ChildStatusProc, &Data); + + osl_waitCondition(Data.m_started, NULL); + osl_destroyCondition(Data.m_started); + + for (i = 0; Data.m_pszArgs[i] != NULL; i++) + free((void *)Data.m_pszArgs[i]); + + for (i = 0; Data.m_pszEnv[i] != NULL; i++) + free((void *)Data.m_pszEnv[i]); + + if ( Data.m_pszDir != 0 ) + { + free((void *)Data.m_pszDir); + } + + osl_destroyThread(hThread); + + if (Data.m_pProcImpl->m_pid != 0) + { + *pProcess = Data.m_pProcImpl; + + if (Options & osl_Process_WAIT) + osl_joinProcess(*pProcess); + + return osl_Process_E_None; + } + + osl_destroyCondition(Data.m_pProcImpl->m_terminated); + free(Data.m_pProcImpl); + + return osl_Process_E_Unknown; +} + + +/****************************************************************************** + * + * Functions for processes + * + *****************************************************************************/ + + +/********************************************** + osl_terminateProcess + *********************************************/ + +oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process) +{ + if (Process == NULL) + return osl_Process_E_Unknown; + + if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0) + { + switch (errno) + { + case EPERM: + return osl_Process_E_NoPermission; + + case ESRCH: + return osl_Process_E_NotFound; + + default: + return osl_Process_E_Unknown; + } + } + + return osl_Process_E_None; +} + +/********************************************** + osl_getProcess + *********************************************/ + +oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident) +{ + oslProcessImpl *pProcImpl; + + if (kill(Ident, 0) != -1) + { + oslProcessImpl* pChild; + + if (ChildListMutex == NULL) + ChildListMutex = osl_createMutex(); + + osl_acquireMutex(ChildListMutex); + + pChild = ChildList; + + /* check if it is one of our child processes */ + while (pChild != NULL) + { + if (Ident == (sal_uInt32) pChild->m_pid) + break; + + pChild = pChild->m_pnext; + } + + pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); + pProcImpl->m_pid = Ident; + pProcImpl->m_terminated = osl_createCondition(); + + if (pChild != NULL) + { + /* process is a child so insert into list */ + pProcImpl->m_pnext = pChild->m_pnext; + pChild->m_pnext = pProcImpl; + + pProcImpl->m_status = pChild->m_status; + + if (osl_checkCondition(pChild->m_terminated)) + osl_setCondition(pProcImpl->m_terminated); + } + else + pProcImpl->m_pnext = NULL; + + osl_releaseMutex(ChildListMutex); + } + else + pProcImpl = NULL; + + return (pProcImpl); +} + +/********************************************** + osl_freeProcessHandle + *********************************************/ + +void SAL_CALL osl_freeProcessHandle(oslProcess Process) +{ + if (Process != NULL) + { + oslProcessImpl *pChild, *pPrev = NULL; + + OSL_ASSERT(ChildListMutex != NULL); + + if ( ChildListMutex == 0 ) + { + return; + } + + osl_acquireMutex(ChildListMutex); + + pChild = ChildList; + + /* remove process from child list */ + while (pChild != NULL) + { + if (pChild == (oslProcessImpl*)Process) + { + if (pPrev != NULL) + pPrev->m_pnext = pChild->m_pnext; + else + ChildList = pChild->m_pnext; + + break; + } + + pPrev = pChild; + pChild = pChild->m_pnext; + } + + osl_releaseMutex(ChildListMutex); + + osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated); + + free(Process); + } +} + +#if defined(LINUX) +struct osl_procStat +{ + /* from 'stat' */ + pid_t pid; /* pid */ + char command[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */ + char state; /* state (running, stopped, ...) */ + pid_t ppid; /* parent pid */ + pid_t pgrp; /* parent group */ + int session; /* session ID */ + int tty; /* no of tty */ + pid_t tpgid; /* group of process owning the tty */ + unsigned long flags; /* flags dunno */ + unsigned long minflt; /* minor page faults */ + unsigned long cminflt; /* minor page faults with children */ + unsigned long majflt; /* major page faults */ + unsigned long cmajflt; /* major page faults with children */ + unsigned long utime; /* no of jiffies in user mode */ + unsigned long stime; /* no of jiffies in kernel mode */ + unsigned long cutime; /* no of jiffies in user mode with children */ + unsigned long cstime; /* no of jiffies in kernel mode with children */ + unsigned long priority; /* nice value + 15 (kernel scheduling prio)*/ + long nice; /* nice value */ + long timeout; /* no of jiffies of next process timeout */ + long itrealvalue; /* no jiffies before next SIGALRM */ + unsigned long starttime; /* process started this no of jiffies after boot */ + unsigned long vsize; /* virtual memory size (in bytes) */ + long rss; /* resident set size (in pages) */ + unsigned long rss_rlim; /* rss limit (in bytes) */ + unsigned long startcode; /* address above program text can run */ + unsigned long endcode; /* address below program text can run */ + unsigned long startstack; /* address of start of stack */ + unsigned long kstkesp; /* current value of 'esp' (stack pointer) */ + unsigned long kstkeip; /* current value of 'eip' (instruction pointer) */ + /* mfe: Linux > 2.1.7x have more signals (88) */ +/*#ifdef LINUX */ + char signal[24]; /* pending signals */ + char blocked[24]; /* blocked signals */ + char sigignore[24]; /* ignored signals */ + char sigcatch[24]; /* catched signals */ +/*#else*/ +/* long long signal;*/ +/* long long blocked;*/ +/* long long sigignore;*/ +/* long long sigcatch;*/ +/*#endif */ + unsigned long wchan; /* 'channel' the process is waiting in */ + unsigned long nswap; /* ? */ + unsigned long cnswap; /* ? */ + + /* from 'status' */ + int ruid; /* real uid */ + int euid; /* effective uid */ + int suid; /* saved uid */ + int fuid; /* file access uid */ + int rgid; /* real gid */ + int egid; /* effective gid */ + int sgid; /* saved gid */ + int fgid; /* file access gid */ + unsigned long vm_size; /* like vsize but on kb */ + unsigned long vm_lock; /* locked pages in kb */ + unsigned long vm_rss; /* like rss but in kb */ + unsigned long vm_data; /* data size */ + unsigned long vm_stack; /* stack size */ + unsigned long vm_exe; /* executable size */ + unsigned long vm_lib; /* library size */ +}; + +/********************************************** + osl_getProcStat + *********************************************/ + +sal_Bool osl_getProcStat(pid_t pid, struct osl_procStat* procstat) +{ + int fd = 0; + sal_Bool bRet = sal_False; + char name[PATH_MAX + 1]; + snprintf(name, sizeof(name), "/proc/%u/stat", pid); + + if ((fd = open(name,O_RDONLY)) >=0 ) + { + char* tmp=0; + char prstatbuf[512]; + memset(prstatbuf,0,512); + bRet = read(fd,prstatbuf,511) == 511; + + close(fd); + /*printf("%s\n\n",prstatbuf);*/ + + if (!bRet) + return sal_False; + + tmp = strrchr(prstatbuf, ')'); + *tmp = '\0'; + memset(procstat->command, 0, sizeof(procstat->command)); + + sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command); + sscanf(tmp + 2, + "%c" + "%i %i %i %i %i" + "%lu %lu %lu %lu %lu" + "%lu %lu %lu %lu" + "%lu %li %li %li" + "%lu %lu %li %lu" + "%lu %lu %lu %lu %lu" + "%s %s %s %s" + "%lu %lu %lu", + &procstat->state, + &procstat->ppid, &procstat->pgrp, &procstat->session, &procstat->tty, &procstat->tpgid, + &procstat->flags, &procstat->minflt, &procstat->cminflt, &procstat->majflt, &procstat->cmajflt, + &procstat->utime, &procstat->stime, &procstat->cutime, &procstat->cstime, + &procstat->priority, &procstat->nice, &procstat->timeout, &procstat->itrealvalue, + &procstat->starttime, &procstat->vsize, &procstat->rss, &procstat->rss_rlim, + &procstat->startcode, &procstat->endcode, &procstat->startstack, &procstat->kstkesp, &procstat->kstkeip, + procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch, + &procstat->wchan, &procstat->nswap, &procstat->cnswap + ); + } + return bRet; +} + +/********************************************** + osl_getProcStatus + *********************************************/ + +sal_Bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat) +{ + int fd = 0; + char name[PATH_MAX + 1]; + snprintf(name, sizeof(name), "/proc/%u/status", pid); + + sal_Bool bRet = sal_False; + + if ((fd = open(name,O_RDONLY)) >=0 ) + { + char* tmp=0; + char prstatusbuf[512]; + memset(prstatusbuf,0,512); + bRet = read(fd,prstatusbuf,511) == 511; + + close(fd); + + /* printf("\n\n%s\n\n",prstatusbuf);*/ + + if (!bRet) + return sal_False; + + tmp = strstr(prstatusbuf,"Uid:"); + if(tmp) + { + sscanf(tmp,"Uid:\t%d\t%d\t%d\t%d", + &procstat->ruid, &procstat->euid, &procstat->suid, &procstat->fuid + ); + } + + + tmp = strstr(prstatusbuf,"Gid:"); + if(tmp) + { + sscanf(tmp,"Gid:\t%d\t%d\t%d\t%d", + &procstat->rgid, &procstat->egid, &procstat->sgid, &procstat->fgid + ); + } + + tmp = strstr(prstatusbuf,"VmSize:"); + if(tmp) + { + sscanf(tmp, + "VmSize: %lu kB\n" + "VmLck: %lu kB\n" + "VmRSS: %lu kB\n" + "VmData: %lu kB\n" + "VmStk: %lu kB\n" + "VmExe: %lu kB\n" + "VmLib: %lu kB\n", + &procstat->vm_size, &procstat->vm_lock, &procstat->vm_rss, &procstat->vm_data, + &procstat->vm_stack, &procstat->vm_exe, &procstat->vm_lib + ); + } + + tmp = strstr(prstatusbuf,"SigPnd:"); + if(tmp) + { + sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s", + procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch + ); + } + } + return bRet; +} + +#endif + +/********************************************** + osl_getProcessInfo + *********************************************/ + +oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo) +{ + pid_t pid; + + if (Process == NULL) + pid = getpid(); + else + pid = ((oslProcessImpl*)Process)->m_pid; + + if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo))) + return osl_Process_E_Unknown; + + pInfo->Fields = 0; + + if (Fields & osl_Process_IDENTIFIER) + { + pInfo->Ident = pid; + pInfo->Fields |= osl_Process_IDENTIFIER; + } + + if (Fields & osl_Process_EXITCODE) + { + if ((Process != NULL) && + osl_checkCondition(((oslProcessImpl*)Process)->m_terminated)) + { + pInfo->Code = ((oslProcessImpl*)Process)->m_status; + pInfo->Fields |= osl_Process_EXITCODE; + } + } + + if (Fields & (osl_Process_HEAPUSAGE | osl_Process_CPUTIMES)) + { + +#if defined(SOLARIS) + + int fd; + sal_Char name[PATH_MAX + 1]; + + snprintf(name, sizeof(name), "/proc/%u", pid); + + if ((fd = open(name, O_RDONLY)) >= 0) + { + prstatus_t prstatus; + + if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0) + { + if (Fields & osl_Process_CPUTIMES) + { + pInfo->UserTime.Seconds = prstatus.pr_utime.tv_sec; + pInfo->UserTime.Nanosec = prstatus.pr_utime.tv_nsec; + pInfo->SystemTime.Seconds = prstatus.pr_stime.tv_sec; + pInfo->SystemTime.Nanosec = prstatus.pr_stime.tv_nsec; + + pInfo->Fields |= osl_Process_CPUTIMES; + } + + if (Fields & osl_Process_HEAPUSAGE) + { + pInfo->HeapUsage = prstatus.pr_brksize; + + pInfo->Fields |= osl_Process_HEAPUSAGE; + } + + close(fd); + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; + } + else + close(fd); + } + +#elif defined(HPUX) + + struct pst_status prstatus; + + if (pstat_getproc(&prstatus, sizeof(prstatus), (size_t)0, pid) == 1) + { + if (Fields & osl_Process_CPUTIMES) + { + pInfo->UserTime.Seconds = prstatus.pst_utime; + pInfo->UserTime.Nanosec = 500000L; + pInfo->SystemTime.Seconds = prstatus.pst_stime; + pInfo->SystemTime.Nanosec = 500000L; + + pInfo->Fields |= osl_Process_CPUTIMES; + } + + if (Fields & osl_Process_HEAPUSAGE) + { + pInfo->HeapUsage = prstatus.pst_vdsize*PAGESIZE; + + pInfo->Fields |= osl_Process_HEAPUSAGE; + } + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; + } + +#elif defined(LINUX) + + if ( (Fields & osl_Process_CPUTIMES) || (Fields & osl_Process_HEAPUSAGE) ) + { + struct osl_procStat procstat; + memset(&procstat,0,sizeof(procstat)); + + if ( (Fields & osl_Process_CPUTIMES) && osl_getProcStat(pid, &procstat) ) + { + /* + * mfe: + * We calculate only time of the process proper. + * Threads are processes, we do not consider their time here! + * (For this, cutime and cstime should be used, it seems not + * to work in 2.0.36) + */ + + long clktck; + unsigned long hz; + unsigned long userseconds; + unsigned long systemseconds; + + clktck = sysconf(_SC_CLK_TCK); + if (clktck < 0) { + return osl_Process_E_Unknown; + } + hz = (unsigned long) clktck; + + userseconds = procstat.utime/hz; + systemseconds = procstat.stime/hz; + + pInfo->UserTime.Seconds = userseconds; + pInfo->UserTime.Nanosec = procstat.utime - (userseconds * hz); + pInfo->SystemTime.Seconds = systemseconds; + pInfo->SystemTime.Nanosec = procstat.stime - (systemseconds * hz); + + pInfo->Fields |= osl_Process_CPUTIMES; + } + + if ( (Fields & osl_Process_HEAPUSAGE) && osl_getProcStatus(pid, &procstat) ) + { + /* + * mfe: + * vm_data (found in status) shows the size of the data segment + * it a rough approximation of the core heap size + */ + pInfo->HeapUsage = procstat.vm_data*1024; + + pInfo->Fields |= osl_Process_HEAPUSAGE; + } + } + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; +#endif + + } + + return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; +} + + +/*********************************************** + helper function for osl_joinProcessWithTimeout + **********************************************/ + +static int is_timeout(const struct timeval* tend) +{ + struct timeval tcurrent; + gettimeofday(&tcurrent, NULL); + return (tcurrent.tv_sec >= tend->tv_sec); +} + +/********************************************** + kill(pid, 0) is usefull for checking if a + process is still alive, but remember that + kill even returns 0 if the process is already + a zombie. + *********************************************/ + +static int is_process_dead(pid_t pid) +{ + return ((-1 == kill(pid, 0)) && (ESRCH == errno)); +} + +/********************************************** + osl_joinProcessWithTimeout + *********************************************/ + +oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout) +{ + oslProcessImpl* pChild = ChildList; + oslProcessError osl_error = osl_Process_E_None; + + OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter"); + OSL_ASSERT(ChildListMutex); + + if (NULL == Process || 0 == ChildListMutex) + return osl_Process_E_Unknown; + + osl_acquireMutex(ChildListMutex); + + /* check if process is a child of ours */ + while (pChild != NULL) + { + if (pChild == (oslProcessImpl*)Process) + break; + + pChild = pChild->m_pnext; + } + + osl_releaseMutex(ChildListMutex); + + if (pChild != NULL) + { + oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout); + + if (osl_cond_result_timeout == cond_res) + osl_error = osl_Process_E_TimedOut; + else if (osl_cond_result_ok != cond_res) + osl_error = osl_Process_E_Unknown; + } + else /* alien process; StatusThread will not be able + to set the condition terminated */ + { + pid_t pid = ((oslProcessImpl*)Process)->m_pid; + + if (pTimeout) + { + int timeout = 0; + struct timeval tend; + + gettimeofday(&tend, NULL); + + tend.tv_sec += pTimeout->Seconds; + + while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0)) + sleep(1); + + if (timeout) + osl_error = osl_Process_E_TimedOut; + } + else /* infinite */ + { + while (!is_process_dead(pid)) + sleep(1); + } + } + return osl_error; +} + +/********************************************** + osl_joinProcess + *********************************************/ + +oslProcessError SAL_CALL osl_joinProcess(oslProcess Process) +{ + return osl_joinProcessWithTimeout(Process, NULL); +} diff --git a/sal/osl/unx/process_impl.cxx b/sal/osl/unx/process_impl.cxx new file mode 100644 index 000000000000..e712b6748e7f --- /dev/null +++ b/sal/osl/unx/process_impl.cxx @@ -0,0 +1,412 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "osl/process.h" + +#ifndef INCLUDED_LIMITS_H +#include <limits.h> +#define INCLUDED_LIMITS_H +#endif + +#ifndef INCLUDED_PTHREAD_H +#include <pthread.h> +#define INCLUDED_PTHREAD_H +#endif + +#ifndef INCLUDED_STDLIB_H +#include <stdlib.h> +#define INCLUDED_STDLIB_H +#endif + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif +#include "osl/diagnose.h" +#include <osl/file.h> +#include "osl/module.h" +#include "osl/thread.h" +#include "rtl/ustring.hxx" + +#ifndef _OSL_FILE_PATH_HELPER_H_ +#include "file_path_helper.h" +#endif + +#ifndef _OSL_UUNXAPI_H_ +#include "uunxapi.h" +#endif + +/*************************************** + osl_bootstrap_getExecutableFile_Impl(). + + @internal + @see rtl_bootstrap + @see #i37371# + + **************************************/ + +extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C(); + + +#if defined(MACOSX) +#include <mach-o/dyld.h> + +oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C() +{ + oslProcessError result = osl_Process_E_NotFound; + + char buffer[PATH_MAX]; + size_t buflen = sizeof(buffer); + +#if __GNUC__ >= 4 && defined(MACOSX) + if (_NSGetExecutablePath (buffer, (uint32_t*)&buflen) == 0) +#else + if (_NSGetExecutablePath (buffer, &buflen) == 0) +#endif + { + /* Determine absolute path. */ + char abspath[PATH_MAX]; + if (realpath (buffer, abspath) != 0) + { + /* Convert from utf8 to unicode. */ + rtl_uString * pAbsPath = 0; + rtl_string2UString ( + &(pAbsPath), + abspath, rtl_str_getLength (abspath), + RTL_TEXTENCODING_UTF8, + OSTRING_TO_OUSTRING_CVTFLAGS); + + if (pAbsPath) + { + /* Convert from path to url. */ + if (osl_getFileURLFromSystemPath (pAbsPath, ppFileURL) == osl_File_E_None) + { + /* Success. */ + result = osl_Process_E_None; + } + rtl_uString_release (pAbsPath); + } + } + } + + return (result); +} + +#elif !defined(NO_DL_FUNCTIONS) +#include <dlfcn.h> + +oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C() +{ + oslProcessError result = osl_Process_E_NotFound; + + /* Determine address of "main()" function. */ + void * addr = dlsym (RTLD_DEFAULT, "main"); + if (addr != 0) + { + /* Determine module URL. */ + if (osl_getModuleURLFromAddress (addr, ppFileURL)) + { + /* Success. */ + result = osl_Process_E_None; + } + } + + return (result); +} + +#else /* NO_DL_FUNCTIONS */ + +oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL +) SAL_THROW_EXTERN_C() +{ + /* Fallback to ordinary osl_getExecutableFile(). */ + return osl_getExecutableFile (ppFileURL); +} + +#endif /* NO_DL_FUNCTIONS */ + +/*************************************** + CommandArgs_Impl. + **************************************/ +struct CommandArgs_Impl +{ + pthread_mutex_t m_mutex; + sal_uInt32 m_nCount; + rtl_uString ** m_ppArgs; +}; + +static struct CommandArgs_Impl g_command_args = +{ + PTHREAD_MUTEX_INITIALIZER, + 0, + 0 +}; + +/*************************************** + osl_getExecutableFile(). + **************************************/ +oslProcessError SAL_CALL osl_getExecutableFile (rtl_uString ** ppustrFile) +{ + oslProcessError result = osl_Process_E_NotFound; + + pthread_mutex_lock (&(g_command_args.m_mutex)); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > 0) + { + /* CommandArgs set. Obtain argv[0]. */ + rtl_uString_assign (ppustrFile, g_command_args.m_ppArgs[0]); + result = osl_Process_E_None; + } + pthread_mutex_unlock (&(g_command_args.m_mutex)); + + return (result); +} + +/*************************************** + osl_getCommandArgCount(). + **************************************/ +sal_uInt32 SAL_CALL osl_getCommandArgCount (void) +{ + sal_uInt32 result = 0; + + pthread_mutex_lock (&(g_command_args.m_mutex)); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > 0) + result = g_command_args.m_nCount - 1; + pthread_mutex_unlock (&(g_command_args.m_mutex)); + + return (result); +} + +/*************************************** + osl_getCommandArg(). + **************************************/ +oslProcessError SAL_CALL osl_getCommandArg (sal_uInt32 nArg, rtl_uString ** strCommandArg) +{ + oslProcessError result = osl_Process_E_NotFound; + + pthread_mutex_lock (&(g_command_args.m_mutex)); + OSL_ASSERT(g_command_args.m_nCount > 0); + if (g_command_args.m_nCount > (nArg + 1)) + { + rtl_uString_assign (strCommandArg, g_command_args.m_ppArgs[nArg + 1]); + result = osl_Process_E_None; + } + pthread_mutex_unlock (&(g_command_args.m_mutex)); + + return (result); +} + +/*************************************** + osl_setCommandArgs(). + **************************************/ +void SAL_CALL osl_setCommandArgs (int argc, char ** argv) +{ + OSL_ASSERT(argc > 0); + pthread_mutex_lock (&(g_command_args.m_mutex)); + OSL_ENSURE (g_command_args.m_nCount == 0, "osl_setCommandArgs(): CommandArgs already set."); + if (g_command_args.m_nCount == 0) + { + rtl_uString** ppArgs = (rtl_uString**)rtl_allocateZeroMemory (argc * sizeof(rtl_uString*)); + if (ppArgs != 0) + { + rtl_TextEncoding encoding = osl_getThreadTextEncoding(); + for (int i = 0; i < argc; i++) + { + rtl_string2UString ( + &(ppArgs[i]), + argv[i], rtl_str_getLength (argv[i]), encoding, + OSTRING_TO_OUSTRING_CVTFLAGS); + } + if (ppArgs[0] != 0) + { + /* see @ osl_getExecutableFile(). */ + if (rtl_ustr_indexOfChar (rtl_uString_getStr(ppArgs[0]), sal_Unicode('/')) == -1) + { + const rtl::OUString PATH (RTL_CONSTASCII_USTRINGPARAM("PATH")); + + rtl_uString * pSearchPath = 0; + osl_getEnvironment (PATH.pData, &pSearchPath); + if (pSearchPath) + { + rtl_uString * pSearchResult = 0; + osl_searchPath (ppArgs[0], pSearchPath, &pSearchResult); + if (pSearchResult) + { + rtl_uString_assign (&(ppArgs[0]), pSearchResult); + rtl_uString_release (pSearchResult); + } + rtl_uString_release (pSearchPath); + } + } + + rtl_uString * pArg0 = 0; + if (realpath_u (ppArgs[0], &pArg0)) + { + osl_getFileURLFromSystemPath (pArg0, &(ppArgs[0])); + rtl_uString_release (pArg0); + } + } + g_command_args.m_nCount = argc; + g_command_args.m_ppArgs = ppArgs; + } + } + pthread_mutex_unlock (&(g_command_args.m_mutex)); +} + +/*************************************** + osl_getEnvironment(). + **************************************/ +oslProcessError SAL_CALL osl_getEnvironment(rtl_uString* pustrEnvVar, rtl_uString** ppustrValue) +{ + oslProcessError result = osl_Process_E_NotFound; + rtl_TextEncoding encoding = osl_getThreadTextEncoding(); + rtl_String* pstr_env_var = 0; + + OSL_PRECOND(pustrEnvVar, "osl_getEnvironment(): Invalid parameter"); + OSL_PRECOND(ppustrValue, "osl_getEnvironment(): Invalid parameter"); + + rtl_uString2String( + &pstr_env_var, + rtl_uString_getStr(pustrEnvVar), rtl_uString_getLength(pustrEnvVar), encoding, + OUSTRING_TO_OSTRING_CVTFLAGS); + if (pstr_env_var != 0) + { + const char* p_env_var = getenv (rtl_string_getStr (pstr_env_var)); + if (p_env_var != 0) + { + rtl_string2UString( + ppustrValue, + p_env_var, strlen(p_env_var), encoding, + OSTRING_TO_OUSTRING_CVTFLAGS); + OSL_ASSERT(*ppustrValue != NULL); + + result = osl_Process_E_None; + } + rtl_string_release(pstr_env_var); + } + + return (result); +} + +/*************************************** + osl_getProcessWorkingDir(). + **************************************/ +oslProcessError SAL_CALL osl_getProcessWorkingDir(rtl_uString **ppustrWorkingDir) +{ + oslProcessError result = osl_Process_E_Unknown; + char buffer[PATH_MAX]; + + OSL_PRECOND(ppustrWorkingDir, "osl_getProcessWorkingDir(): Invalid parameter"); + + if (getcwd (buffer, sizeof(buffer)) != 0) + { + rtl_uString* ustrTmp = 0; + + rtl_string2UString( + &ustrTmp, + buffer, strlen(buffer), osl_getThreadTextEncoding(), + OSTRING_TO_OUSTRING_CVTFLAGS); + if (ustrTmp != 0) + { + if (osl_getFileURLFromSystemPath (ustrTmp, ppustrWorkingDir) == osl_File_E_None) + result = osl_Process_E_None; + rtl_uString_release (ustrTmp); + } + } + + return (result); +} + +/****************************************************************************** + * + * new functions to set/return the current process locale + * + *****************************************************************************/ + +struct ProcessLocale_Impl +{ + pthread_mutex_t m_mutex; + rtl_Locale * m_pLocale; +}; + +static struct ProcessLocale_Impl g_process_locale = +{ + PTHREAD_MUTEX_INITIALIZER, + 0 +}; + +extern "C" void _imp_getProcessLocale( rtl_Locale ** ); +extern "C" int _imp_setProcessLocale( rtl_Locale * ); + +/********************************************** + osl_getProcessLocale(). + *********************************************/ +oslProcessError SAL_CALL osl_getProcessLocale( rtl_Locale ** ppLocale ) +{ + OSL_PRECOND(ppLocale, "osl_getProcessLocale(): Invalid parameter."); + + pthread_mutex_lock(&(g_process_locale.m_mutex)); + + if (g_process_locale.m_pLocale == 0) + _imp_getProcessLocale (&(g_process_locale.m_pLocale)); + *ppLocale = g_process_locale.m_pLocale; + + pthread_mutex_unlock (&(g_process_locale.m_mutex)); + + return (osl_Process_E_None); +} + +/********************************************** + osl_setProcessLocale(). + *********************************************/ +oslProcessError SAL_CALL osl_setProcessLocale( rtl_Locale * pLocale ) +{ + oslProcessError result = osl_Process_E_Unknown; + + OSL_PRECOND(pLocale, "osl_setProcessLocale(): Invalid parameter."); + + pthread_mutex_lock(&(g_process_locale.m_mutex)); + if (_imp_setProcessLocale (pLocale) == 0) + { + g_process_locale.m_pLocale = pLocale; + result = osl_Process_E_None; + } + pthread_mutex_unlock (&(g_process_locale.m_mutex)); + + return (result); +} diff --git a/sal/osl/unx/procimpl.h b/sal/osl/unx/procimpl.h new file mode 100644 index 000000000000..1a08d72ffe5a --- /dev/null +++ b/sal/osl/unx/procimpl.h @@ -0,0 +1,50 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_PROCIMPL_H_ +#define _OSL_PROCIMPL_H_ + +#include <osl/process.h> +#include <osl/conditn.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _oslProcessImpl { + pid_t m_pid; + oslCondition m_terminated; + int m_status; + struct _oslProcessImpl* m_pnext; +} oslProcessImpl; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/unx/profile.c b/sal/osl/unx/profile.c new file mode 100644 index 000000000000..c77a27543261 --- /dev/null +++ b/sal/osl/unx/profile.c @@ -0,0 +1,2221 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/profile.h> +#include <osl/process.h> +#include <osl/thread.h> +#include <rtl/alloc.h> +#include <osl/util.h> + +#define LINES_INI 32 +#define LINES_ADD 10 +#define SECTIONS_INI 5 +#define SECTIONS_ADD 3 +#define ENTRIES_INI 5 +#define ENTRIES_ADD 3 + + +#define STR_INI_EXTENSION "rc" +#define STR_INI_METAHOME "?~" +#define STR_INI_METASYS "?$" +#define STR_INI_METACFG "?^" +#define STR_INI_METAINS "?#" + +#define STR_INI_BOOLYES "yes" +#define STR_INI_BOOLON "on" +#define STR_INI_BOOLONE "1" +#define STR_INI_BOOLNO "no" +#define STR_INI_BOOLOFF "off" +#define STR_INI_BOOLZERO "0" + +#define FLG_USER 0x00FF +#define FLG_AUTOOPEN 0x0100 +#define FLG_MODIFIED 0x0200 + +#define SVERSION_LOCATION STR_INI_METACFG +#define SVERSION_FALLBACK STR_INI_METASYS +#define SVERSION_NAME "sversion" +#define SVERSION_SECTION "Versions" +#define SVERSION_SOFFICE "StarOffice" +#define SVERSION_PROFILE "sofficerc" +#define SVERSION_OPTION "userid:" +#define SVERSION_DIRS { "bin", "program" } +#define SVERSION_USER "user" + +#define DEFAULT_PMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) + +#define _BUILD_STR_(n) # n +#define BUILD_STR(n) _BUILD_STR_(n) + + +/*#define DEBUG_OSL_PROFILE*/ +/*#define TRACE_OSL_PROFILE*/ + +/*****************************************************************************/ +/* Data Type Definition */ +/*****************************************************************************/ + +typedef time_t osl_TStamp; + +typedef enum _osl_TLockMode +{ + un_lock, read_lock, write_lock +} osl_TLockMode; + +typedef struct _osl_TFile +{ + int m_Handle; + sal_Char* m_pReadPtr; + sal_Char m_ReadBuf[512]; + sal_Char* m_pWriteBuf; + sal_uInt32 m_nWriteBufLen; + sal_uInt32 m_nWriteBufFree; +} osl_TFile; + +typedef struct _osl_TProfileEntry +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; +} osl_TProfileEntry; + +typedef struct _osl_TProfileSection +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; + sal_uInt32 m_NoEntries; + sal_uInt32 m_MaxEntries; + osl_TProfileEntry* m_Entries; +} osl_TProfileSection; + + +/* + Profile-data structure hidden behind oslProfile: +*/ +typedef struct _osl_TProfileImpl +{ + sal_uInt32 m_Flags; + osl_TFile* m_pFile; + osl_TStamp m_Stamp; + sal_Char m_FileName[PATH_MAX + 1]; + sal_uInt32 m_NoLines; + sal_uInt32 m_MaxLines; + sal_uInt32 m_NoSections; + sal_uInt32 m_MaxSections; + sal_Char** m_Lines; + osl_TProfileSection* m_Sections; + pthread_mutex_t m_AccessLock; + sal_Bool m_bIsValid; +} osl_TProfileImpl; + + +/*****************************************************************************/ +/* Static Module Function Declarations */ +/*****************************************************************************/ + +static osl_TFile* openFileImpl(const sal_Char* pszFilename, oslProfileOption ProfileFlags); +static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags); +static sal_Bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode); +static sal_Bool OslProfile_rewindFile(osl_TFile* pFile, sal_Bool bTruncate); +static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile); + +static sal_Char* OslProfile_getLine(osl_TFile* pFile); +static sal_Bool OslProfile_putLine(osl_TFile* pFile, const sal_Char *pszLine); +static sal_Char* stripBlanks(sal_Char* String, sal_uInt32* pLen); +static sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line); +static sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo); +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo); +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + sal_Char* Entry, sal_uInt32 Len); +static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, sal_Char* Entry, sal_uInt32 Len); +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry); +static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len); +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection); +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section, + const sal_Char* Entry, sal_uInt32 *pNoEntry); +static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile); +static sal_Bool storeProfile(osl_TProfileImpl* pProfile, sal_Bool bCleanup); +static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable); +static sal_Bool releaseProfile(osl_TProfileImpl* pProfile); + +static sal_Bool writeProfileImpl (osl_TFile* pFile); +static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl*); +static sal_Bool osl_ProfileSwapProfileNames(osl_TProfileImpl*); +static void osl_ProfileGenerateExtension(sal_Char* pszFileName, sal_Char* pszExtension, sal_Char* pszTmpName); +static oslProfile SAL_CALL osl_psz_openProfile(const sal_Char *pszProfileName, oslProfileOption Flags); + +/* implemented in file.c */ +extern oslFileError FileURLToPath( char *, size_t, rtl_uString* ); + +/*****************************************************************************/ +/* Exported Module Functions */ +/*****************************************************************************/ +oslProfile SAL_CALL osl_openProfile(rtl_uString *ustrProfileName, oslProfileOption Options) +{ + char profilePath[PATH_MAX] = ""; + + if ( ustrProfileName != 0 && ustrProfileName->buffer[0] != 0 ) + FileURLToPath( profilePath, PATH_MAX, ustrProfileName ); + + return osl_psz_openProfile( profilePath,Options ); +} + + +static oslProfile SAL_CALL osl_psz_openProfile(const sal_Char *pszProfileName, oslProfileOption Flags) +{ + osl_TFile* pFile; + osl_TProfileImpl* pProfile; + sal_Char Filename[PATH_MAX]; + sal_Bool bRet = sal_False; + + Filename[0] = '\0'; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_openProfile\n"); +#endif + +#ifdef DEBUG_OSL_PROFILE + Flags=osl_Profile_FLUSHWRITE; + + OSL_TRACE("opening '%s'\n",pszProfileName); + if ( Flags == osl_Profile_DEFAULT ) + { + OSL_TRACE("with osl_Profile_DEFAULT\n"); + } + if ( Flags & osl_Profile_SYSTEM ) + { + OSL_TRACE("with osl_Profile_SYSTEM\n"); + } + if ( Flags & osl_Profile_READLOCK ) + { + OSL_TRACE("with osl_Profile_READLOCK\n"); + } + if ( Flags & osl_Profile_WRITELOCK ) + { + OSL_TRACE("with osl_Profile_WRITELOCK\n"); + } + if ( Flags & osl_Profile_FLUSHWRITE ) + { + OSL_TRACE("with osl_Profile_FLUSHWRITE\n"); + } +#endif + + + if ( ( pFile = openFileImpl(pszProfileName, Flags ) ) == NULL ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_openProfile [not opened]\n"); +#endif + return (NULL); + } + + + pProfile = (osl_TProfileImpl*)calloc(1, sizeof(osl_TProfileImpl)); + + if ( pProfile == 0 ) + { + return 0; + } + + pProfile->m_Flags = Flags & FLG_USER; + + if ( Flags & ( osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) ) + { + pProfile->m_pFile = pFile; + } + + pthread_mutex_init(&(pProfile->m_AccessLock),PTHREAD_MUTEXATTR_DEFAULT); + pProfile->m_bIsValid=sal_True; + + pProfile->m_Stamp = OslProfile_getFileStamp(pFile); + bRet=loadProfile(pFile, pProfile); + bRet &= realpath(pszProfileName, pProfile->m_FileName) != NULL; + OSL_ASSERT(bRet); + + if (pProfile->m_pFile == NULL) + closeFileImpl(pFile,pProfile->m_Flags); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_openProfile [ok]\n"); +#endif + return (pProfile); +} + +sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_closeProfile\n"); +#endif + + if ( Profile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [profile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pProfile->m_AccessLock)); + + if ( pProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pProfile->m_bIsValid); + pthread_mutex_unlock(&(pProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [not valid]\n"); +#endif + return sal_False; + } + + pProfile->m_bIsValid=sal_False; + + if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) && ( pProfile->m_Flags & FLG_MODIFIED ) ) + { + pProfile = acquireProfile(Profile,sal_True); + + if ( pProfile != 0 ) + { + bRet=storeProfile(pProfile, sal_True); + OSL_ASSERT(bRet); + } + } + else + { + pProfile = acquireProfile(Profile,sal_False); + } + + + if ( pProfile == 0 ) + { + pthread_mutex_unlock(&(pProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [pProfile==0]\n"); +#endif + return sal_False; + } + + if (pProfile->m_pFile != NULL) + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + + pProfile->m_pFile = NULL; + pProfile->m_FileName[0] = '\0'; + + /* release whole profile data types memory */ + if ( pProfile->m_NoLines > 0) + { + unsigned int idx=0; + if ( pProfile->m_Lines != 0 ) + { + for ( idx = 0 ; idx < pProfile->m_NoLines ; ++idx) + { + if ( pProfile->m_Lines[idx] != 0 ) + { + free(pProfile->m_Lines[idx]); + pProfile->m_Lines[idx]=0; + } + } + free(pProfile->m_Lines); + pProfile->m_Lines=0; + } + if ( pProfile->m_Sections != 0 ) + { + /*osl_TProfileSection* pSections=pProfile->m_Sections;*/ + for ( idx = 0 ; idx < pProfile->m_NoSections ; ++idx ) + { + if ( pProfile->m_Sections[idx].m_Entries != 0 ) + { + free(pProfile->m_Sections[idx].m_Entries); + pProfile->m_Sections[idx].m_Entries=0; + } + } + free(pProfile->m_Sections); + pProfile->m_Sections=0; + } + } + + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + + pthread_mutex_destroy(&(pProfile->m_AccessLock)); + + free(pProfile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_closeProfile [ok]\n"); +#endif + return (sal_True); +} + + +sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*) Profile; + osl_TFile* pFile; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_flushProfile()\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [pProfile == 0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pProfile->m_AccessLock)); + + if ( pProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pProfile->m_bIsValid); + pthread_mutex_unlock(&(pProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile [not valid]\n"); +#endif + return sal_False; + } + + pFile = pProfile->m_pFile; + if ( !( pFile != 0 && pFile->m_Handle >= 0 ) ) + { + pthread_mutex_unlock(&(pProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [invalid file]\n"); +#endif + return sal_False; + } + + if ( pProfile->m_Flags & FLG_MODIFIED ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("swapping to storeprofile\n"); +#endif + bRet = storeProfile(pProfile,sal_False); + OSL_ASSERT(bRet); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_flushProfile() [ok]\n"); +#endif + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + return bRet; +} + +static sal_Bool writeProfileImpl(osl_TFile* pFile) +{ + int BytesWritten=0; +#if OSL_DEBUG_LEVEL > 1 + unsigned int nLen=0; +#endif + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileImpl()\n"); +#endif + + if ( !( pFile != 0 && pFile->m_Handle >= 0 ) || ( pFile->m_pWriteBuf == 0 ) ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileImpl() [invalid args]\n"); +#endif + return sal_False; + } + +#if OSL_DEBUG_LEVEL > 1 + nLen=strlen(pFile->m_pWriteBuf); + OSL_ASSERT(nLen == (pFile->m_nWriteBufLen - pFile->m_nWriteBufFree)); +#endif + + BytesWritten = write(pFile->m_Handle, pFile->m_pWriteBuf, pFile->m_nWriteBufLen - pFile->m_nWriteBufFree); + + if ( BytesWritten <= 0 ) + { + OSL_TRACE("write failed '%s'\n",strerror(errno)); + return (sal_False); + } + +#if OSL_DEBUG_LEVEL > 1 + OSL_ASSERT( + BytesWritten >= 0 && SAL_INT_CAST(unsigned int, BytesWritten) == nLen); +#endif + + free(pFile->m_pWriteBuf); + pFile->m_pWriteBuf=0; + pFile->m_nWriteBufLen=0; + pFile->m_nWriteBufFree=0; +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileImpl() [ok]\n"); +#endif + return sal_True; +} + + +sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Char* pszString, sal_uInt32 MaxLen, + const sal_Char* pszDefault) +{ + sal_uInt32 NoEntry; + sal_Char* pStr=0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile=0; + osl_TProfileImpl* pTmpProfile=0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileString\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pTmpProfile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pProfile->m_bIsValid); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [not valid]\n"); +#endif + return sal_False; + } + + pProfile = acquireProfile(Profile, sal_False); + + if ( pProfile == NULL ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pProfile==0]\n"); +#endif + return (sal_False); + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) && + (NoEntry < pSec->m_NoEntries) && + ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line], + '=')) != NULL)) + { + pStr++; + } + else + { + pStr=(sal_Char*)pszDefault; + } + + if ( pStr != 0 ) + { + pStr = stripBlanks(pStr, NULL); + MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr); + pStr = stripBlanks(pStr, &MaxLen); + strncpy(pszString, pStr, MaxLen); + pszString[MaxLen] = '\0'; + } + } + else + { /* not implemented */ } + + + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + if ( pStr == 0 ) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [pStr==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileString [ok]\n"); +#endif + + return (sal_True); +} + + +sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Bool Default) +{ + sal_Char Line[32]; + Line[0] = '\0'; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileBool\n"); +#endif + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + if ((strcasecmp(Line, STR_INI_BOOLYES) == 0) || + (strcasecmp(Line, STR_INI_BOOLON) == 0) || + (strcasecmp(Line, STR_INI_BOOLONE) == 0)) + Default = sal_True; + else + if ((strcasecmp(Line, STR_INI_BOOLNO) == 0) || + (strcasecmp(Line, STR_INI_BOOLOFF) == 0) || + (strcasecmp(Line, STR_INI_BOOLZERO) == 0)) + Default = sal_False; + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileBool [ok]\n"); +#endif + + return (Default); +} + + +sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_uInt32 FirstId, const sal_Char* Strings[], + sal_uInt32 Default) +{ + sal_uInt32 i; + sal_Char Line[256]; + Line[0] = '\0'; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_readProfileIdent\n"); +#endif + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + i = 0; + while (Strings[i] != NULL) + { + if (strcasecmp(Line, Strings[i]) == 0) + { + Default = i + FirstId; + break; + } + i++; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_readProfileIdent [ok]\n"); +#endif + return (Default); +} + +sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + const sal_Char* pszString) +{ + sal_uInt32 i; + sal_Bool bRet = sal_False; + sal_uInt32 NoEntry; + sal_Char* pStr; + sal_Char* Line = 0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + osl_TProfileImpl* pTmpProfile = 0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileString\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [pTmpProfile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pTmpProfile->m_bIsValid); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not valid]\n"); +#endif + return sal_False; + } + + pProfile=acquireProfile(Profile, sal_True); + + if (pProfile == NULL) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [pProfile==0]\n"); +#endif + return (sal_False); + } + + Line = (sal_Char*) malloc(strlen(pszEntry)+strlen(pszString)+48); + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == NULL) + { + Line[0] = '\0'; + addLine(pProfile, Line); + + Line[0] = '['; + strcpy(&Line[1], pszSection); + Line[1 + strlen(pszSection)] = ']'; + Line[2 + strlen(pszSection)] = '\0'; + + if (((pStr = addLine(pProfile, Line)) == NULL) || + (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection)))) + { + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + free(Line); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not added]\n"); +#endif + return (sal_False); + } + + pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1]; + NoEntry = pSec->m_NoEntries; + } + + Line[0] = '\0'; + strcpy(&Line[0], pszEntry); + Line[0 + strlen(pszEntry)] = '='; + strcpy(&Line[1 + strlen(pszEntry)], pszString); + + if (NoEntry >= pSec->m_NoEntries) + { + if (pSec->m_NoEntries > 0) + i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1; + else + i = pSec->m_Line + 1; + + if (((pStr = insertLine(pProfile, Line, i)) == NULL) || + (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry)))) + { + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + free(Line); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [not inserted]\n"); +#endif + return (sal_False); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + else + { + i = pSec->m_Entries[NoEntry].m_Line; + free(pProfile->m_Lines[i]); + pProfile->m_Lines[i] = strdup(Line); + setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry)); + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else { + /* not implemented */ + } + + bRet = releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + if ( Line!= 0 ) + { + free(Line); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileString [ok]\n"); +#endif + + return bRet; +} + + +sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_Bool Value) +{ + sal_Bool bRet=sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileBool\n"); +#endif + + if (Value) + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE); + else + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileBool [ok]\n"); +#endif + + return bRet; +} + + +sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile, + const sal_Char* pszSection, const sal_Char* pszEntry, + sal_uInt32 FirstId, const sal_Char* Strings[], + sal_uInt32 Value) +{ + int i, n; + sal_Bool bRet=sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_writeProfileIdent\n"); +#endif + + for (n = 0; Strings[n] != NULL; n++); + + if ((i = Value - FirstId) >= n) + bRet=sal_False; + else + bRet = osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_writeProfileIdent\n"); +#endif + return bRet; +} + + +sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile, + const sal_Char *pszSection, const sal_Char *pszEntry) +{ + sal_uInt32 NoEntry; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + osl_TProfileImpl* pTmpProfile = 0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_removeProfileEntry\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [pProfile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pTmpProfile->m_bIsValid); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [not valid]\n"); +#endif + return sal_False; + } + + + pProfile = acquireProfile(Profile, sal_True); + + if (pProfile == NULL) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [pProfile==0]\n"); +#endif + return (sal_False); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != NULL) && + (NoEntry < pSec->m_NoEntries)) + { + removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line); + removeEntry(pSec, NoEntry); + if (pSec->m_NoEntries == 0) + { + removeLine(pProfile, pSec->m_Line); + + /* remove any empty separation line */ + if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0')) + removeLine(pProfile, pSec->m_Line - 1); + + removeSection(pProfile, pSec); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else + { /* not implemented */ } + + + bRet = releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_removeProfileEntry [ok]\n"); +#endif + return bRet; +} + + +sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile, const sal_Char *pszSection, + sal_Char* pszBuffer, sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + sal_uInt32 NoEntry; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + osl_TProfileImpl* pTmpProfile = 0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_getProfileSectionEntries\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [pTmpProfile==0]\n"); +#endif + return sal_False; + + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pTmpProfile->m_bIsValid); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [not valid]\n"); +#endif + + return sal_False; + } + + pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [pProfile=0]\n"); +#endif + + return (0); + } + + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != NULL) + { + if (MaxLen != 0) + { + for (i = 0; i < pSec->m_NoEntries; i++) + { + if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len); + n += pSec->m_Entries[i].m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pSec->m_NoEntries; i++) + n += pSec->m_Entries[i].m_Len + 1; + + n += 1; + } + } + else + n = 0; + } + else { + /* not implemented */ + } + + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSectionEntries [ok]\n"); +#endif + + return (n); +} + +sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile, sal_Char* pszBuffer, sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + osl_TProfileSection* pSec; + osl_TProfileImpl* pProfile = 0; + osl_TProfileImpl* pTmpProfile = 0; + sal_Bool bRet = sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_getProfileSections\n"); +#endif + + pTmpProfile = (osl_TProfileImpl*) Profile; + + if ( pTmpProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSections [pTmpProfile==0]\n"); +#endif + return sal_False; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( pTmpProfile->m_bIsValid == sal_False ) + { + OSL_ASSERT(pTmpProfile->m_bIsValid); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSections [not valid]\n"); +#endif + return sal_False; + } + + pProfile = acquireProfile(Profile, sal_False); + + if (pProfile == NULL) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSections [pProfile==0]\n"); +#endif + return (0); + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (MaxLen != 0) + { + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if ((n + pSec->m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], + pSec->m_Len); + n += pSec->m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pProfile->m_NoSections; i++) + n += pProfile->m_Sections[i].m_Len + 1; + + n += 1; + } + } + else + { /* not implemented */ } + + + bRet=releaseProfile(pProfile); + OSL_ASSERT(bRet); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_getProfileSections [ok]\n"); +#endif + + return (n); +} + +/*****************************************************************************/ +/* Static Module Functions */ +/*****************************************************************************/ + +static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile) +{ + struct stat status; + + if ( (pFile->m_Handle < 0) || (fstat(pFile->m_Handle, &status) < 0) ) + { + return (0); + } + + + return (status.st_mtime); +} + +static sal_Bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode) +{ + struct flock lock; + /* boring hack, but initializers for static vars must be constant */ + static sal_Bool bIsInitialized = sal_False; + static sal_Bool bLockingDisabled; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In OslProfile_lockFile\n"); +#endif + + if ( !bIsInitialized ) + { + sal_Char* pEnvValue; + pEnvValue = getenv( "STAR_PROFILE_LOCKING_DISABLED" ); + + if ( pEnvValue == 0 ) + { + bLockingDisabled = sal_False; + + } + else + { + bLockingDisabled = sal_True; + } + + bIsInitialized = sal_True; + } + + if (pFile->m_Handle < 0) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out OslProfile_lockFile [invalid file handle]\n"); +#endif + return (sal_False); + } + + + if ( bLockingDisabled ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out OslProfile_lockFile [locking disabled]\n"); +#endif + return (sal_True); + } + + + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + switch (eMode) + { + case un_lock: + lock.l_type = F_UNLCK; + break; + + case read_lock: + lock.l_type = F_RDLCK; + break; + + case write_lock: + lock.l_type = F_WRLCK; + break; + } + +#ifndef MACOSX // not MAC OSX + if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 ) +#else + /* Mac OSX will return ENOTSUP for webdav drives so we should ignore it */ + if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 && errno != ENOTSUP ) +#endif /* MACOSX */ + { + OSL_TRACE("fcntl returned -1 (%s)\n",strerror(errno)); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out OslProfile_lockFile [fcntl F_SETLKW]\n"); +#endif + return sal_False; + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out OslProfile_lockFile [ok]\n"); +#endif + return sal_True; +} + +static osl_TFile* openFileImpl(const sal_Char* pszFilename, oslProfileOption ProfileFlags ) +{ + int Flags; + osl_TFile* pFile = (osl_TFile*) calloc(1, sizeof(osl_TFile)); + sal_Bool bWriteable = sal_False; + + if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("setting bWriteable to TRUE\n"); +#endif + bWriteable=sal_True; + } + + if (! bWriteable) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("opening '%s' read only\n",pszFilename); +#endif + + pFile->m_Handle = open(pszFilename, O_RDONLY); + /* mfe: argghh!!! do not check if the file could be openend */ + /* default mode expects it that way!!! */ + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("opening '%s' read/write\n",pszFilename); +#endif + if (((pFile->m_Handle = open(pszFilename, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PMODE)) < 0) && + ((pFile->m_Handle = open(pszFilename, O_RDWR)) < 0)) + { + free(pFile); +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out openFileImpl [open read/write]\n"); +#endif + return (NULL); + } + } + + /* set close-on-exec flag */ + if ((Flags = fcntl(pFile->m_Handle, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + fcntl(pFile->m_Handle, F_SETFD, Flags); + } + + pFile->m_pWriteBuf=0; + pFile->m_nWriteBufFree=0; + pFile->m_nWriteBufLen=0; + + if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) ) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("locking '%s' file\n",pszFilename); +#endif + OslProfile_lockFile(pFile, bWriteable ? write_lock : read_lock); + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out openFileImpl [ok]\n"); +#endif + return (pFile); +} + +static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags) +{ + osl_TStamp stamp = 0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In closeFileImpl\n"); +#endif + + if ( pFile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out closeFileImpl [pFile == 0]\n"); +#endif + return stamp; + } + + if ( pFile->m_Handle >= 0 ) + { + stamp = OslProfile_getFileStamp(pFile); + + if ( Flags & (osl_Profile_WRITELOCK | osl_Profile_WRITELOCK ) ) + { + OslProfile_lockFile(pFile, un_lock); + } + + close(pFile->m_Handle); + pFile->m_Handle = -1; + } + + + if ( pFile->m_pWriteBuf ) + { + free(pFile->m_pWriteBuf); + } + + free(pFile); + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out closeFileImpl [ok]\n"); +#endif + + return(stamp); +} + +static sal_Bool OslProfile_rewindFile(osl_TFile* pFile, sal_Bool bTruncate) +{ + sal_Bool bRet = sal_True; +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In osl_OslProfile_rewindFile\n"); +#endif + + if (pFile->m_Handle >= 0) + { + pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("rewinding\n"); +#endif + bRet = (lseek(pFile->m_Handle, SEEK_SET, 0L) == 0L); + + if (bTruncate) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("truncating\n"); +#endif + bRet &= (ftruncate(pFile->m_Handle, 0L) == 0); + } + + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out osl_OslProfile_rewindFile [ok]\n"); +#endif + return bRet; +} + + +static sal_Char* OslProfile_getLine(osl_TFile* pFile) +{ + int Max, Free, Bytes, nLineBytes = 0; + sal_Char* pChr; + sal_Char* pLine = NULL; + sal_Char* pNewLine; + + if ( pFile == 0 ) + { + return 0; + } + + if (pFile->m_Handle < 0) + return NULL; + + do + { + Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf); + + if (Bytes <= 1) + { + /* refill buffer */ + memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes); + pFile->m_pReadPtr = pFile->m_ReadBuf; + + Free = sizeof(pFile->m_ReadBuf) - Bytes; + + if ((Max = read(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free)) < 0) + { + OSL_TRACE("read failed '%s'\n",strerror(errno)); + + if( pLine ) + rtl_freeMemory( pLine ); + pLine = NULL; + break; + } + + if (Max < Free) + { + if ((Max == 0) && ! pLine) + break; + + pFile->m_ReadBuf[Bytes + Max] = '\0'; + } + } + + for (pChr = pFile->m_pReadPtr; + (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') && + (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)); + pChr++); + + Max = pChr - pFile->m_pReadPtr; + pNewLine = (sal_Char*) rtl_allocateMemory( nLineBytes + Max + 1 ); + if( pLine ) + { + memcpy( pNewLine, pLine, nLineBytes ); + rtl_freeMemory( pLine ); + } + memcpy(pNewLine+nLineBytes, pFile->m_pReadPtr, Max); + nLineBytes += Max; + pNewLine[ nLineBytes ] = 0; + pLine = pNewLine; + + if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)) + { + if (*pChr != '\0') + { + if ((pChr[0] == '\r') && (pChr[1] == '\n')) + pChr += 2; + else + pChr += 1; + } + + if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) && + (*pChr == '\0')) + pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + + /* setting Max to -1 indicates terminating read loop */ + Max = -1; + } + + pFile->m_pReadPtr = pChr; + } + while (Max > 0); + + return pLine; +} + +static sal_Bool OslProfile_putLine(osl_TFile* pFile, const sal_Char *pszLine) +{ + unsigned int Len = strlen(pszLine); + +#ifdef DEBUG_OSL_PROFILE + int strLen=0; +#endif + + if ( pFile == 0 || pFile->m_Handle < 0 ) + { + return (sal_False); + } + + if ( pFile->m_pWriteBuf == 0 ) + { + pFile->m_pWriteBuf = (sal_Char*) malloc(Len+3); + pFile->m_nWriteBufLen = Len+3; + pFile->m_nWriteBufFree = Len+3; + } + else + { + if ( pFile->m_nWriteBufFree <= Len + 3 ) + { + sal_Char* pTmp; + + pTmp=(sal_Char*) realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) ); + if ( pTmp == 0 ) + { + return sal_False; + } + pFile->m_pWriteBuf = pTmp; + pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len ); + pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2; + memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree); + } + } + + + + memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1); +#ifdef DEBUG_OSL_PROFILE + strLen = strlen(pFile->m_pWriteBuf); +#endif + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\n'; + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\0'; + + pFile->m_nWriteBufFree-=Len+1; + + return sal_True; +} + +/* platform specific end */ + +static sal_Char* stripBlanks(sal_Char* String, sal_uInt32* pLen) +{ + if ( ( pLen != NULL ) && ( *pLen != 0 ) ) + { + while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t')) + (*pLen)--; + + while ( (*String == ' ') || (*String == '\t') ) + { + String++; + (*pLen)--; + } + } + else + while ( (*String == ' ') || (*String == '\t') ) + String++; + + return (String); +} + +static sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == NULL) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *)); + memset(pProfile->m_Lines,0,pProfile->m_MaxLines * sizeof(sal_Char *)); + } + else + { + unsigned int idx=0; + unsigned int oldmax=pProfile->m_MaxLines; + + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(sal_Char *)); + for ( idx = oldmax ; idx < pProfile->m_MaxLines ; ++idx ) + { + pProfile->m_Lines[idx]=0; + } + } + + if (pProfile->m_Lines == NULL) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return (NULL); + } + + } + + if ( pProfile->m_Lines != 0 && pProfile->m_Lines[pProfile->m_NoLines] != 0 ) + { + free(pProfile->m_Lines[pProfile->m_NoLines]); + } + pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line); + + return (pProfile->m_Lines[pProfile->m_NoLines - 1]); +} + +static sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == NULL) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = (sal_Char **)malloc(pProfile->m_MaxLines * sizeof(sal_Char *)); + memset(pProfile->m_Lines,0,pProfile->m_MaxLines * sizeof(sal_Char *)); + } + else + { + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = (sal_Char **)realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(sal_Char *)); + + memset(&pProfile->m_Lines[pProfile->m_NoLines], + 0, + (pProfile->m_MaxLines - pProfile->m_NoLines - 1) * sizeof(sal_Char*)); + } + + if (pProfile->m_Lines == NULL) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return (NULL); + } + } + + LineNo = LineNo > pProfile->m_NoLines ? pProfile->m_NoLines : LineNo; + + if (LineNo < pProfile->m_NoLines) + { + sal_uInt32 i, n; + osl_TProfileSection* pSec; + + memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo], + (pProfile->m_NoLines - LineNo) * sizeof(sal_Char *)); + + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line >= LineNo) + pSec->m_Line++; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line >= LineNo) + pSec->m_Entries[n].m_Line++; + } + } + + pProfile->m_NoLines++; + + pProfile->m_Lines[LineNo] = strdup(Line); + + return (pProfile->m_Lines[LineNo]); +} + +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo) +{ + if (LineNo < pProfile->m_NoLines) + { + free(pProfile->m_Lines[LineNo]); + pProfile->m_Lines[LineNo]=0; + if (pProfile->m_NoLines - LineNo > 1) + { + sal_uInt32 i, n; + osl_TProfileSection* pSec; + + memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1], + (pProfile->m_NoLines - LineNo - 1) * sizeof(sal_Char *)); + + memset(&pProfile->m_Lines[pProfile->m_NoLines - 1], + 0, + (pProfile->m_MaxLines - pProfile->m_NoLines) * sizeof(sal_Char*)); + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line > LineNo) + pSec->m_Line--; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line > LineNo) + pSec->m_Entries[n].m_Line--; + } + } + else + { + pProfile->m_Lines[LineNo] = 0; + } + + pProfile->m_NoLines--; + } + + return; +} + +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + sal_Char* Entry, sal_uInt32 Len) +{ + Entry = stripBlanks(Entry, &Len); + pSection->m_Entries[NoEntry].m_Line = Line; + pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line]; + pSection->m_Entries[NoEntry].m_Len = Len; + + return; +} + +static sal_Bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, sal_Char* Entry, sal_uInt32 Len) +{ + if (pSection != NULL) + { + if (pSection->m_NoEntries >= pSection->m_MaxEntries) + { + if (pSection->m_Entries == NULL) + { + pSection->m_MaxEntries = ENTRIES_INI; + pSection->m_Entries = (osl_TProfileEntry *)malloc( + pSection->m_MaxEntries * sizeof(osl_TProfileEntry)); + } + else + { + pSection->m_MaxEntries += ENTRIES_ADD; + pSection->m_Entries = (osl_TProfileEntry *)realloc(pSection->m_Entries, + pSection->m_MaxEntries * sizeof(osl_TProfileEntry)); + } + + if (pSection->m_Entries == NULL) + { + pSection->m_NoEntries = 0; + pSection->m_MaxEntries = 0; + return (sal_False); + } + } + + pSection->m_NoEntries++; + + Entry = stripBlanks(Entry, &Len); + setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line, + Entry, Len); + + return (sal_True); + } + + return (sal_False); +} + +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry) +{ + if (NoEntry < pSection->m_NoEntries) + { + if (pSection->m_NoEntries - NoEntry > 1) + { + memmove(&pSection->m_Entries[NoEntry], + &pSection->m_Entries[NoEntry + 1], + (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry)); + pSection->m_Entries[pSection->m_NoEntries - 1].m_Line=0; + pSection->m_Entries[pSection->m_NoEntries - 1].m_Offset=0; + pSection->m_Entries[pSection->m_NoEntries - 1].m_Len=0; + } + + pSection->m_NoEntries--; + } + + return; +} + +static sal_Bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len) +{ + if (pProfile->m_NoSections >= pProfile->m_MaxSections) + { + if (pProfile->m_Sections == NULL) + { + pProfile->m_MaxSections = SECTIONS_INI; + pProfile->m_Sections = (osl_TProfileSection *)malloc(pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + memset(pProfile->m_Sections,0,pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + } + else + { + unsigned int idx=0; + unsigned int oldmax=pProfile->m_MaxSections; + + pProfile->m_MaxSections += SECTIONS_ADD; + pProfile->m_Sections = (osl_TProfileSection *)realloc(pProfile->m_Sections, + pProfile->m_MaxSections * sizeof(osl_TProfileSection)); + for ( idx = oldmax ; idx < pProfile->m_MaxSections ; ++idx ) + { + pProfile->m_Sections[idx].m_Entries=0; + } + } + + if (pProfile->m_Sections == NULL) + { + pProfile->m_NoSections = 0; + pProfile->m_MaxSections = 0; + return (sal_False); + } + } + + pProfile->m_NoSections++; + + if ( pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries != 0 ) + { + free(pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries); + } + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = NULL; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries = 0; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0; + + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line]; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len; + + return (sal_True); +} + +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection) +{ + sal_uInt32 Section; + + if ((Section = pSection - pProfile->m_Sections) < pProfile->m_NoSections) + { + free (pSection->m_Entries); + pSection->m_Entries=0; + if (pProfile->m_NoSections - Section > 1) + { + memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1], + (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection)); + + memset(&pProfile->m_Sections[pProfile->m_NoSections - 1], + 0, + (pProfile->m_MaxSections - pProfile->m_NoSections) * sizeof(osl_TProfileSection)); + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = 0; + } + else + { + pSection->m_Entries = 0; + } + + pProfile->m_NoSections--; + } + + return; +} + +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section, + const sal_Char* Entry, sal_uInt32 *pNoEntry) +{ +static sal_uInt32 Sect = 0; + sal_uInt32 i, n; + sal_uInt32 Len; + const sal_Char* pStr; + osl_TProfileSection* pSec=0; + + Len = strlen(Section); + + n = Sect; + + for (i = 0; i < pProfile->m_NoSections; i++) + { + n %= pProfile->m_NoSections; + pSec = &pProfile->m_Sections[n]; + if ((Len == pSec->m_Len) && + (strncasecmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len) + == 0)) + break; + n++; + } + + Sect = n; + + if (i < pProfile->m_NoSections) + { + Len = strlen(Entry); + + *pNoEntry = pSec->m_NoEntries; + + for (i = 0; i < pSec->m_NoEntries; i++) + { + pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset]; + if ((Len == pSec->m_Entries[i].m_Len) && + (strncasecmp(Entry, pStr, pSec->m_Entries[i].m_Len) + == 0)) + { + *pNoEntry = i; + break; + } + } + } + else + pSec = NULL; + + return (pSec); +} + +static sal_Bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile) +{ + sal_uInt32 i; + sal_Char* pStr; + sal_Char* pChar; + + sal_Char* pLine; + sal_Char* bWasAdded = NULL; + + pProfile->m_NoLines = 0; + pProfile->m_NoSections = 0; + + if ( pFile == 0 ) + { + return sal_False; + } + + if ( pProfile == 0 ) + { + return sal_False; + } + + OSL_VERIFY(OslProfile_rewindFile(pFile, sal_False)); + + while ( ( pLine=OslProfile_getLine(pFile) ) != 0 ) + { + bWasAdded = addLine( pProfile, pLine ); + rtl_freeMemory( pLine ); + OSL_ASSERT(bWasAdded); + if ( ! bWasAdded ) + return (sal_False); + } + + for (i = 0; i < pProfile->m_NoLines; i++) + { + pStr = (sal_Char *)stripBlanks(pProfile->m_Lines[i], NULL); + + if ((*pStr == '\0') || (*pStr == ';')) + continue; + + if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == NULL) || + ((pChar - pStr) <= 2)) + { + /* insert entry */ + + if (pProfile->m_NoSections < 1) + continue; + + if ((pChar = strchr(pStr, '=')) == NULL) + pChar = pStr + strlen(pStr); + + if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1], + i, pStr, pChar - pStr)) + { + OSL_ASSERT(0); + continue; + } + + } + else + { + /* new section */ + + if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1)) + { + OSL_ASSERT(0); + continue; + } + + } + } + + return (sal_True); +} + +static sal_Bool storeProfile(osl_TProfileImpl* pProfile, sal_Bool bCleanup) +{ +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In storeProfile\n"); +#endif + + if (pProfile->m_Lines != NULL) + { + if (pProfile->m_Flags & FLG_MODIFIED) + { + sal_uInt32 i; + + osl_TFile* pTmpFile = osl_openTmpProfileImpl(pProfile); + + if ( pTmpFile == 0 ) + { + return sal_False; + } + + OSL_VERIFY(OslProfile_rewindFile(pTmpFile, sal_True)); + + for ( i = 0 ; i < pProfile->m_NoLines ; i++ ) + { + OSL_VERIFY(OslProfile_putLine(pTmpFile, pProfile->m_Lines[i])); + } + + if ( ! writeProfileImpl(pTmpFile) ) + { + if ( pTmpFile->m_pWriteBuf != 0 ) + { + free(pTmpFile->m_pWriteBuf); + } + + pTmpFile->m_pWriteBuf=0; + pTmpFile->m_nWriteBufLen=0; + pTmpFile->m_nWriteBufFree=0; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out storeProfile [not flushed]\n"); +#endif + closeFileImpl(pTmpFile,pProfile->m_Flags); + + return sal_False; + } + + pProfile->m_Flags &= ~FLG_MODIFIED; + + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + closeFileImpl(pTmpFile,pProfile->m_Flags); + + osl_ProfileSwapProfileNames(pProfile); + + pProfile->m_pFile = openFileImpl(pProfile->m_FileName,pProfile->m_Flags); + + } + + if (bCleanup) + { + while (pProfile->m_NoLines > 0) + removeLine(pProfile, pProfile->m_NoLines - 1); + + free(pProfile->m_Lines); + pProfile->m_Lines = NULL; + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + + while (pProfile->m_NoSections > 0) + removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]); + + free(pProfile->m_Sections); + pProfile->m_Sections = NULL; + pProfile->m_NoSections = 0; + pProfile->m_MaxSections = 0; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out storeProfile [ok]\n"); +#endif + return (sal_True); +} + + +static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl* pProfile) +{ + osl_TFile* pFile=0; + sal_Char* pszExtension = "tmp"; + sal_Char pszTmpName[PATH_MAX]; + oslProfileOption PFlags=0; + + pszTmpName[0] = '\0'; + + /* generate tmp profilename */ + osl_ProfileGenerateExtension(pProfile->m_FileName,pszExtension,pszTmpName); + + if ( pszTmpName[0] == 0 ) + { + return 0; + } + + if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) ) + { + PFlags |= osl_Profile_WRITELOCK; + } + + /* open this file */ + pFile = openFileImpl(pszTmpName,pProfile->m_Flags | PFlags); + + + /* return new pFile */ + return pFile; +} + +static sal_Bool osl_ProfileSwapProfileNames(osl_TProfileImpl* pProfile) +{ + sal_Bool bRet = sal_False; + + sal_Char pszBakFile[PATH_MAX]; + sal_Char pszTmpFile[PATH_MAX]; + sal_Char pszIniFile[PATH_MAX]; + + pszBakFile[0] = '\0'; + pszTmpFile[0] = '\0'; + pszIniFile[0] = '\0'; + + osl_ProfileGenerateExtension(pProfile->m_FileName,"bak",pszBakFile); + + strcpy(pszIniFile,pProfile->m_FileName); + + osl_ProfileGenerateExtension(pProfile->m_FileName,"tmp",pszTmpFile); + + /* unlink bak */ + unlink( pszBakFile ); + + /* rename ini bak */ + rename( pszIniFile, pszBakFile ); + + /* rename tmp ini */ + rename( pszTmpFile, pszIniFile ); + + return bRet; +} + + +static void osl_ProfileGenerateExtension(sal_Char* pszFileName, sal_Char* pszExtension, sal_Char* pszTmpName) +{ + + strcpy(pszTmpName,pszFileName); + strcat(pszTmpName,"."); + strcat(pszTmpName,pszExtension); + + return; +} + + +static osl_TProfileImpl* acquireProfile(oslProfile Profile, sal_Bool bWriteable) +{ + osl_TProfileImpl* pProfile = (osl_TProfileImpl*)Profile; + oslProfileOption PFlags=0; + sal_Bool bRet=sal_False; + + if ( bWriteable ) + { + PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK; + } + else + { + PFlags = osl_Profile_DEFAULT; + } + + + if (pProfile == NULL) + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("AUTOOPEN MODE\n"); +#endif + + if ( ( pProfile = (osl_TProfileImpl*) osl_openProfile(0, PFlags ) ) != NULL ) + { + pProfile->m_Flags |= FLG_AUTOOPEN; + } + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("try to acquire\n"); +#endif + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ))) + { + osl_TStamp Stamp; + +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("Profile acquire DEFAULT MODE\n"); +#endif + if (! (pProfile->m_pFile = openFileImpl(pProfile->m_FileName, pProfile->m_Flags | PFlags ))) + return NULL; + + Stamp = OslProfile_getFileStamp(pProfile->m_pFile); + + if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp))) + { + pProfile->m_Stamp = Stamp; + + bRet=loadProfile(pProfile->m_pFile, pProfile); + OSL_ASSERT(bRet); + } + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("Profile acquire READ/WRITELOCK MODE\n"); +#endif + /* A readlock file could not be written */ + if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable) + { + return (NULL); + } + } + } + } + + return (pProfile); +} + +static sal_Bool releaseProfile(osl_TProfileImpl* pProfile) +{ + sal_Bool bRet=sal_False; + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("In releaseProfile\n"); +#endif + + if ( pProfile == 0 ) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [profile==0]\n"); +#endif + return sal_False; + } + + if (pProfile->m_Flags & FLG_AUTOOPEN) + { +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [AUTOOPEN]\n"); +#endif + return (osl_closeProfile((oslProfile)pProfile)); + } + else + { +#ifdef DEBUG_OSL_PROFILE + OSL_TRACE("DEFAULT MODE\n"); +#endif + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ))) + { + if (pProfile->m_Flags & FLG_MODIFIED) + { + bRet=storeProfile(pProfile, sal_False); + OSL_ASSERT(bRet); + } + + + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + pProfile->m_pFile = NULL; + } + } + +#ifdef TRACE_OSL_PROFILE + OSL_TRACE("Out releaseProfile [ok]\n"); +#endif + return (sal_True); +} diff --git a/sal/osl/unx/salinit.cxx b/sal/osl/unx/salinit.cxx new file mode 100644 index 000000000000..7090a381235c --- /dev/null +++ b/sal/osl/unx/salinit.cxx @@ -0,0 +1,43 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sal.hxx" +#include "sal/config.h" + +#include "osl/process.h" +#include "sal/main.h" +#include "sal/types.h" + +extern "C" { + +void SAL_CALL sal_detail_initialize(int argc, char ** argv) { + osl_setCommandArgs(argc, argv); +} + +void SAL_CALL sal_detail_deinitialize() {} + +} diff --git a/sal/osl/unx/secimpl.h b/sal/osl/unx/secimpl.h new file mode 100644 index 000000000000..1d8f2aaa9419 --- /dev/null +++ b/sal/osl/unx/secimpl.h @@ -0,0 +1,47 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_SECURITYIMPL_H_ +#define _OSL_SECURITYIMPL_H_ + +#include <pwd.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _oslSecurityImpl { + struct passwd m_pPasswd; + char m_buffer[1]; /* should be a C99 flexible array member */ +} oslSecurityImpl; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/unx/security.c b/sal/osl/unx/security.c new file mode 100644 index 000000000000..d08326e65ebe --- /dev/null +++ b/sal/osl/unx/security.c @@ -0,0 +1,862 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <stddef.h> + +/* Solaris 8 has no C99 stdint.h, and Solaris generally seems not to miss it for + SIZE_MAX: */ +#if !defined __SUNPRO_C +#include <stdint.h> +#endif + +#include "system.h" + +#include <osl/security.h> +#include <osl/diagnose.h> + +#include "osl/thread.h" +#include "osl/file.h" + +#if defined LINUX || defined SOLARIS +#include <crypt.h> +#endif + +#include "secimpl.h" + +#ifndef NOPAM +#ifndef PAM_BINARY_MSG +#define PAM_BINARY_MSG 6 +#endif +#endif + +static oslSecurityError SAL_CALL +osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd, + oslSecurity* pSecurity); +sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax); +static sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax); +static sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax); +static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax); + +static sal_Bool sysconf_SC_GETPW_R_SIZE_MAX(size_t * value) { +#if defined _SC_GETPW_R_SIZE_MAX + long m; + errno = 0; + m = sysconf(_SC_GETPW_R_SIZE_MAX); + if (m == -1) { + /* _SC_GETPW_R_SIZE_MAX has no limit; some platforms like certain + FreeBSD versions support sysconf(_SC_GETPW_R_SIZE_MAX) in a broken + way and always set EINVAL, so be resilient here: */ + return sal_False; + } else { + OSL_ASSERT(m >= 0 && (unsigned long) m < SIZE_MAX); + *value = (size_t) m; + return sal_True; + } +#else + /* some platforms like Mac OS X 1.3 do not define _SC_GETPW_R_SIZE_MAX: */ + return sal_False; +#endif +} + +static oslSecurityImpl * growSecurityImpl( + oslSecurityImpl * impl, size_t * bufSize) +{ + size_t n = 0; + oslSecurityImpl * p = NULL; + if (impl == NULL) { + if (!sysconf_SC_GETPW_R_SIZE_MAX(&n)) { + /* choose something sensible (the callers of growSecurityImpl will + detect it if the allocated buffer is too small: */ + n = 1024; + } + } else if (*bufSize <= SIZE_MAX / 2) { + n = 2 * *bufSize; + } + if (n != 0) { + if (n <= SIZE_MAX - offsetof(oslSecurityImpl, m_buffer)) { + *bufSize = n; + n += offsetof(oslSecurityImpl, m_buffer); + } else { + *bufSize = SIZE_MAX - offsetof(oslSecurityImpl, m_buffer); + n = SIZE_MAX; + } + p = realloc(impl, n); + } + if (p == NULL) { + free(impl); + } + return p; +} + +static void deleteSecurityImpl(oslSecurityImpl * impl) { + free(impl); +} + +oslSecurity SAL_CALL osl_getCurrentSecurity() +{ + size_t n = 0; + oslSecurityImpl * p = NULL; + for (;;) { + struct passwd * found; + p = growSecurityImpl(p, &n); + if (p == NULL) { + return NULL; + } + switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) { + case ERANGE: + break; + case 0: + if (found != NULL) { + return p; + } + /* fall through */ + default: + deleteSecurityImpl(p); + return NULL; + } + } +} + + +#if defined LINUX && !defined NOPAM + +/* + * + * osl Routines for Pluggable Authentication Modules (PAM) + * tested with Linux-PAM 0.66 on Redhat-6.0 and + * Linux-PAM 0.64 on RedHat-5.2, + * XXX Will probably not run on PAM 0.59 or prior, since + * number of pam_response* responses has changed + * + */ + +#include <security/pam_appl.h> + +typedef struct { + char* name; + char* password; +} sal_PamData; + +typedef struct { + int (*pam_start)(const char *service_name, const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh); + int (*pam_end) (pam_handle_t *pamh, int pam_status); + int (*pam_authenticate) (pam_handle_t *pamh, int flags); + int (*pam_acct_mgmt) (pam_handle_t *pamh, int flags); +} sal_PamModule; + +/* + * Implement a pam-conversation callback-routine, + * it just supply name and password instead of prompting the user. + * I guess that echo-off means 'ask for password' and echo-on means + * 'ask for user-name'. In fact I've never been asked anything else + * than the password + * XXX Please notice that if a pam-module does ask anything else, we + * are completely lost, and a pam-module is free to do so + * XXX + */ + +static int +osl_PamConversation (int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + int i; + sal_Bool error; + sal_PamData *pam_data; + struct pam_response *p_reply; + + /* resource initialization */ + pam_data = (sal_PamData*) appdata_ptr; + p_reply = (struct pam_response *) calloc( num_msg, + sizeof(struct pam_response)); + if ( p_reply == NULL || pam_data == NULL ) + { + if ( p_reply != NULL ) + free ( p_reply ); + *response = NULL; + return PAM_CONV_ERR; + } + + /* pseudo dialog */ + error = sal_False; + for ( i = 0; i < num_msg ; i++ ) + { + switch ( msgm[ i ]->msg_style ) + { + case PAM_PROMPT_ECHO_OFF: + p_reply[ i ].resp_retcode = 0; + p_reply[ i ].resp = strdup( pam_data->password ); + break; + case PAM_PROMPT_ECHO_ON: + p_reply[ i ].resp_retcode = 0; + p_reply[ i ].resp = strdup( pam_data->name ); + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + case PAM_BINARY_PROMPT: + case PAM_BINARY_MSG: + p_reply[ i ].resp_retcode = 0; + p_reply[ i ].resp = NULL; + break; + default: + error = sal_True; + break; + } + } + + /* free resources on error */ + if ( error ) + { + for ( i = 0; i < num_msg ; i++ ) + if ( p_reply[ i ].resp ) + { + memset ( p_reply[ i ].resp, 0, + strlen( p_reply[ i ].resp ) ); + free ( p_reply[ i ].resp ); + } + free ( p_reply ); + + *response = NULL; + return PAM_CONV_ERR; + } + + /* well done */ + *response = p_reply; + return PAM_SUCCESS; +} + +#ifndef PAM_LINK +/* + * avoid linking against libpam.so, since it is not available on all systems, + * instead load-on-call, returns structure which holds pointer to + * pam-functions, + * library is never closed in case of success + */ + +static sal_PamModule* osl_getPAM() +{ + static sal_PamModule *pam_module = NULL; + static sal_Bool load_once = sal_False; + + if ( !load_once ) + { + /* get library-handle. cannot use osl-module, since + RTLD_GLOBAL is required for PAM-0.64 RH 5.2 + (but not for PAM-0.66 RH 6.0) */ + void *pam_hdl; + + pam_hdl = dlopen( "libpam.so.0", RTLD_GLOBAL | RTLD_LAZY ); + + if ( pam_hdl != NULL ) + pam_module = (sal_PamModule*)calloc( 1, sizeof(sal_PamModule) ); + + /* load functions */ + if ( pam_module != NULL ) + { + pam_module->pam_acct_mgmt = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_acct_mgmt" ); + pam_module->pam_authenticate + = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_authenticate" ); + pam_module->pam_end = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_end" ); + pam_module->pam_start = (int (*)(const char *, const char *, const struct pam_conv *, pam_handle_t **)) dlsym ( pam_hdl, "pam_start" ); + + /* free resources, if not completely successful */ + if ( (pam_module->pam_start == NULL) + || (pam_module->pam_end == NULL) + || (pam_module->pam_authenticate == NULL) + || (pam_module->pam_acct_mgmt == NULL) ) + { + free( pam_module ); + pam_module = NULL; + dlclose( pam_hdl ); + } + } + + /* never try again */ + load_once = sal_True; + } + + return pam_module; +} +#endif + +/* + * User Identification using PAM + */ + +static sal_Bool +osl_PamAuthentification( const sal_Char* name, const sal_Char* password ) +{ + sal_Bool success = sal_False; + +#ifndef PAM_LINK + sal_PamModule* pam_module; + + pam_module = osl_getPAM(); + if ( pam_module != NULL ) + { +#endif + pam_handle_t *pam_handle = NULL; + struct pam_conv pam_conversation; + sal_PamData pam_data; + + int return_value; + + pam_data.name = (char*) name; + pam_data.password = (char*) password; + + pam_conversation.conv = osl_PamConversation; + pam_conversation.appdata_ptr = (void*)(&pam_data); + +#ifndef PAM_LINK + return_value = pam_module->pam_start( "su", name, + &pam_conversation, &pam_handle); +#else + return_value = pam_start( "su", name, + &pam_conversation, &pam_handle); +#endif + if (return_value == PAM_SUCCESS ) +#ifndef PAM_LINK + return_value = pam_module->pam_authenticate(pam_handle, 0); +#else + return_value = pam_authenticate(pam_handle, 0); +#endif + if (return_value == PAM_SUCCESS ) +#ifndef PAM_LINK + return_value = pam_module->pam_acct_mgmt(pam_handle, 0); + pam_module->pam_end( pam_handle, return_value ); +#else + return_value = pam_acct_mgmt(pam_handle, 0); + pam_end( pam_handle, return_value ); +#endif + + success = (sal_Bool)(return_value == PAM_SUCCESS); +#ifndef PAM_LINK + } +#endif + + return success; +} + + +#ifndef CRYPT_LINK +/* dummy crypt, matches the interface of + crypt() but does not encrypt at all */ +static const sal_Char* SAL_CALL +osl_noCrypt ( const sal_Char *key, const sal_Char *salt ) +{ + (void) salt; /* unused */ + return key; +} + +/* load-on-call crypt library and crypt symbol */ +static void* SAL_CALL +osl_getCrypt() +{ + static char* (*crypt_sym)(const char*, const char*) = NULL; + static sal_Bool load_once = sal_False; + + if ( !load_once ) + { + void * crypt_library; + + crypt_library = dlopen( "libcrypt.so.1", RTLD_GLOBAL | RTLD_LAZY ); /* never closed */ + if ( crypt_library != NULL ) + crypt_sym = (char* (*)(const char *, const char *)) dlsym(crypt_library, "crypt" ); + if ( crypt_sym == NULL ) /* no libcrypt or libcrypt without crypt */ + crypt_sym = (char* (*)(const char *, const char *)) &osl_noCrypt; + + load_once = sal_True; + } + + return (void*)crypt_sym; +} + +/* replacement for crypt function for password encryption, uses either + strong encryption of dlopen'ed libcrypt.so.1 or dummy implementation + with no encryption. Objective target is to avoid linking against + libcrypt (not available on caldera open linux 2.2 #63822#) */ +static sal_Char* SAL_CALL +osl_dynamicCrypt ( const sal_Char *key, const sal_Char *salt ) +{ + char* (*dynamic_crypt)(char *, char *); + + dynamic_crypt = (char * (*)(char *, char *)) osl_getCrypt(); + + return dynamic_crypt( (sal_Char*)key, (sal_Char*)salt ); +} +#endif + +/* + * compare an encrypted and an unencrypted password for equality + * returns true if passwords are equal, false otherwise + * Note: uses crypt() and a mutex instead of crypt_r() since crypt_r needs + * more than 128KByte of external buffer for struct crypt_data + */ + +static sal_Bool SAL_CALL +osl_equalPasswords ( const sal_Char *pEncryptedPassword, const sal_Char *pPlainPassword ) +{ + static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER; + + sal_Bool success; + sal_Char salt[3]; + sal_Char *encrypted_plain; + + salt[0] = pEncryptedPassword[0]; + salt[1] = pEncryptedPassword[1]; + salt[2] = '\0'; + + pthread_mutex_lock(&crypt_mutex); + +#ifndef CRYPT_LINK + encrypted_plain = (sal_Char *)osl_dynamicCrypt( pPlainPassword, salt ); +#else + encrypted_plain = (sal_Char *)crypt( pPlainPassword, salt ); +#endif + success = (sal_Bool) (strcmp(pEncryptedPassword, encrypted_plain) == 0); + + pthread_mutex_unlock(&crypt_mutex); + + return success; +} + +#endif /* defined LINUX && !defined NOPAM */ +oslSecurityError SAL_CALL osl_loginUser( + rtl_uString *ustrUserName, + rtl_uString *ustrPassword, + oslSecurity *pSecurity + ) +{ + oslSecurityError Error; + rtl_String* strUserName=0; + rtl_String* strPassword=0; + sal_Char* pszUserName=0; + sal_Char* pszPassword=0; + + if ( ustrUserName != 0 ) + { + + rtl_uString2String( &strUserName, + rtl_uString_getStr(ustrUserName), + rtl_uString_getLength(ustrUserName), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszUserName = rtl_string_getStr(strUserName); + } + + + if ( ustrPassword != 0 ) + { + rtl_uString2String( &strPassword, + rtl_uString_getStr(ustrPassword), + rtl_uString_getLength(ustrPassword), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszPassword = rtl_string_getStr(strPassword); + } + + + Error=osl_psz_loginUser(pszUserName,pszPassword,pSecurity); + + if ( strUserName != 0 ) + { + rtl_string_release(strUserName); + } + + if ( strPassword) + { + rtl_string_release(strPassword); + } + + + return Error; +} + + +static oslSecurityError SAL_CALL +osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd, + oslSecurity* pSecurity) +{ +#if defined NETBSD || defined SCO || defined AIX || defined FREEBSD || \ + defined MACOSX + + return osl_Security_E_None; + +#else + + oslSecurityError nError = osl_Security_E_Unknown; + oslSecurityImpl * p = NULL; + if (pszUserName != NULL && pszPasswd != NULL && pSecurity != NULL) { + /* get nis or normal password, should succeed for any known user, but + perhaps the password is wrong (i.e. 'x') if shadow passwords are in + use or authentication must be done by PAM */ + size_t n = 0; + int err = 0; + struct passwd * found = NULL; + for (;;) { + p = growSecurityImpl(p, &n); + if (p == NULL) { + break; + } + err = getpwnam_r( + pszUserName, &p->m_pPasswd, p->m_buffer, n, &found); + if (err != ERANGE) { + break; + } + } + if (p != NULL && err == 0) { + if (found == NULL) { + nError = osl_Security_E_UserUnknown; + } else { +#if defined LINUX && !defined NOPAM + /* only root is able to read the /etc/shadow passwd, a normal + user even can't read his own encrypted passwd */ + if (osl_equalPasswords(p->m_pPasswd.pw_passwd, pszPasswd) || + osl_PamAuthentification(pszUserName, pszPasswd)) + { + nError = osl_Security_E_None; + } else { + char buffer[1024]; + struct spwd result_buf; + struct spwd * pShadowPasswd; + buffer[0] = '\0'; + if (getspnam_r( + pszUserName, &result_buf, buffer, sizeof buffer, + &pShadowPasswd) == 0 && + pShadowPasswd != NULL) + { + nError = + osl_equalPasswords( + pShadowPasswd->sp_pwdp, pszPasswd) + ? osl_Security_E_None + : osl_Security_E_WrongPassword; + } else if (getuid() == 0) { + /* mfe: Try to verify the root-password via nis */ + if (getspnam_r( + "root", &result_buf, buffer, sizeof buffer, + &pShadowPasswd) == 0 && + pShadowPasswd != NULL && + osl_equalPasswords( + pShadowPasswd->sp_pwdp, pszPasswd)) + { + nError = osl_Security_E_None; + } else { + /* mfe: we can't get via nis (glibc2.0.x has bug in + getspnam_r) we try it with the normal getspnam */ + static pthread_mutex_t pwmutex = + PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&pwmutex); + pShadowPasswd = getspnam("root"); + pthread_mutex_unlock(&pwmutex); + nError = + ((pShadowPasswd != NULL && + osl_equalPasswords( + pShadowPasswd->sp_pwdp, pszPasswd)) || + osl_PamAuthentification("root", pszPasswd)) + ? osl_Security_E_None + : osl_Security_E_WrongPassword; + } + } + } +#else + char buffer[1024]; + struct spwd spwdStruct; + buffer[0] = '\0'; +#ifndef NEW_SHADOW_API + if (getspnam_r(pszUserName, &spwdStruct, buffer, sizeof buffer) != NULL) +#else + if (getspnam_r(pszUserName, &spwdStruct, buffer, sizeof buffer, NULL) == 0) +#endif + { + char salt[3]; + char * cryptPasswd; + strncpy(salt, spwdStruct.sp_pwdp, 2); + salt[2] = '\0'; + cryptPasswd = (char *) crypt(pszPasswd, salt); + if (strcmp(spwdStruct.sp_pwdp, cryptPasswd) == 0) { + nError = osl_Security_E_None; + } else if (getuid() == 0 && +#ifndef NEW_SHADOW_API + (getspnam_r("root", &spwdStruct, buffer, sizeof buffer) != NULL)) +#else + (getspnam_r("root", &spwdStruct, buffer, sizeof buffer, NULL) == 0)) +#endif + { + /* if current process is running as root, allow to logon + as any other user */ + strncpy(salt, spwdStruct.sp_pwdp, 2); + salt[2] = '\0'; + cryptPasswd = (char *) crypt(pszPasswd, salt); + if (strcmp(spwdStruct.sp_pwdp, cryptPasswd) == 0) { + nError = osl_Security_E_None; + } + } else { + nError = osl_Security_E_WrongPassword; + } + } +#endif + } + } + } + if (nError == osl_Security_E_None) { + *pSecurity = p; + } else { + deleteSecurityImpl(p); + *pSecurity = NULL; + } + return nError; + +#endif +} + +oslSecurityError SAL_CALL osl_loginUserOnFileServer( + rtl_uString *strUserName, + rtl_uString *strPasswd, + rtl_uString *strFileServer, + oslSecurity *pSecurity + ) +{ + (void) strUserName; /* unused */ + (void) strPasswd; /* unused */ + (void) strFileServer; /* unused */ + (void) pSecurity; /* unused */ + return osl_Security_E_UserUnknown; +} + + +sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent) +{ + sal_Bool bRet=sal_False; + sal_Char pszIdent[1024]; + + pszIdent[0] = '\0'; + + bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent)); + + rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*ustrIdent != NULL); + + return bRet; +} + + +sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax) +{ + sal_Char buffer[32]; + sal_Int32 nChr; + + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid); + if ( nChr < 0 || SAL_INT_CAST(sal_uInt32, nChr) >= sizeof(buffer) + || SAL_INT_CAST(sal_uInt32, nChr) >= nMax ) + return sal_False; /* leave *pszIdent unmodified in case of failure */ + + memcpy(pszIdent, buffer, nChr+1); + return sal_True; +} + +sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName) +{ + sal_Bool bRet=sal_False; + sal_Char pszName[1024]; + + pszName[0] = '\0'; + + bRet = osl_psz_getUserName(Security,pszName,sizeof(pszName)); + + rtl_string2UString( ustrName, pszName, rtl_str_getLength( pszName ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*ustrName != NULL); + + return bRet; +} + + + +static sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + strncpy(pszName, pSecImpl->m_pPasswd.pw_name, nMax); + + return sal_True; +} + +sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory) +{ + sal_Bool bRet=sal_False; + sal_Char pszDirectory[PATH_MAX]; + + pszDirectory[0] = '\0'; + + bRet = osl_psz_getHomeDir(Security,pszDirectory,sizeof(pszDirectory)); + + if ( bRet == sal_True ) + { + rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pustrDirectory != NULL); + osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory ); + } + + return bRet; +} + + +static sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + /* if current user, check also environment for HOME */ + if (getuid() == pSecImpl->m_pPasswd.pw_uid) + { + sal_Char *pStr = NULL; +#ifdef SOLARIS + char buffer[8192]; + + struct passwd pwd; + struct passwd *ppwd; + +#ifdef _POSIX_PTHREAD_SEMANTICS + if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) ) + ppwd = NULL; +#else + ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) ); +#endif + + if ( ppwd ) + pStr = ppwd->pw_dir; +#else + pStr = getenv("HOME"); +#endif + + if ((pStr != NULL) && (strlen(pStr) > 0) && + (access(pStr, 0) == 0)) + strncpy(pszDirectory, pStr, nMax); + else + strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax); + } + else + strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax); + + return sal_True; +} + +sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory) +{ + sal_Bool bRet = sal_False; + sal_Char pszDirectory[PATH_MAX]; + + pszDirectory[0] = '\0'; + + bRet = osl_psz_getConfigDir(Security,pszDirectory,sizeof(pszDirectory)); + + if ( bRet == sal_True ) + { + rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); + OSL_ASSERT(*pustrDirectory != NULL); + osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory ); + } + + return bRet; +} + +#ifndef MACOSX + +static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax) +{ + sal_Char *pStr = getenv("XDG_CONFIG_HOME"); + + if ((pStr == NULL) || (strlen(pStr) == 0) || + (access(pStr, 0) != 0)) + return (osl_psz_getHomeDir(Security, pszDirectory, nMax)); + + strncpy(pszDirectory, pStr, nMax); + return sal_True; +} + +#else + +/* + * FIXME: rewrite to use more flexible + * NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) + * as soon as we can bumb the baseline to Tiger (for NSApplicationSupportDirectory) and have + * support for Objective-C in the build environment + */ + +#define MACOSX_CONFIG_DIR "/Library/Application Support" +static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax) +{ + if( osl_psz_getHomeDir(Security, pszDirectory, nMax - sizeof(MACOSX_CONFIG_DIR) + 1) ) + { + strcat( pszDirectory, MACOSX_CONFIG_DIR ); + return sal_True; + } + + return sal_False; +} + +#endif + +sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security) +{ + oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security; + + if (pSecImpl == NULL) + return sal_False; + + if (pSecImpl->m_pPasswd.pw_uid != 0) + return (sal_False); + + return (sal_True); +} + +void SAL_CALL osl_freeSecurityHandle(oslSecurity Security) +{ + deleteSecurityImpl(Security); +} + + +sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security) +{ + (void) Security; /* unused */ + return sal_False; +} + +void SAL_CALL osl_unloadUserProfile(oslSecurity Security) +{ + (void) Security; /* unused */ +} diff --git a/sal/osl/unx/semaphor.c b/sal/osl/unx/semaphor.c new file mode 100644 index 000000000000..c514b2dacff6 --- /dev/null +++ b/sal/osl/unx/semaphor.c @@ -0,0 +1,314 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/semaphor.h> +#include <osl/diagnose.h> + +#ifndef OSL_USE_SYS_V_SEMAPHORE + +/* This is the (default) POSIX thread-local semaphore variant */ + +/* + Implemetation notes: + The void* represented by oslSemaphore is used + as a pointer to an sem_t struct +*/ + +/*****************************************************************************/ +/* osl_createSemaphore */ +/*****************************************************************************/ + +oslSemaphore SAL_CALL osl_createSemaphore(sal_uInt32 initialCount) +{ + int ret = 0; + oslSemaphore Semaphore; + + Semaphore= malloc(sizeof(sem_t)); + + OSL_ASSERT(Semaphore); /* ptr valid? */ + + if ( Semaphore == 0 ) + { + return 0; + } + + /* unnamed semaphore, not shared between processes */ + + ret= sem_init((sem_t*)Semaphore, 0, initialCount); + + /* create failed? */ + if (ret != 0) + { + OSL_TRACE("osl_createSemaphore failed. Errno: %d; %s\n", + errno, + strerror(errno)); + + free(Semaphore); + Semaphore = NULL; + } + + return Semaphore; +} + +/*****************************************************************************/ +/* osl_destroySemaphore */ +/*****************************************************************************/ +void SAL_CALL osl_destroySemaphore(oslSemaphore Semaphore) +{ + if(Semaphore) /* ptr valid? */ + { + sem_destroy((sem_t*)Semaphore); + free(Semaphore); + } +} + +/*****************************************************************************/ +/* osl_acquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireSemaphore(oslSemaphore Semaphore) { + + OSL_ASSERT(Semaphore != 0); /* abort in debug mode */ + + if (Semaphore != 0) /* be tolerant in release mode */ + { + return (sem_wait((sem_t*)Semaphore) == 0); + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_tryToAcquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireSemaphore(oslSemaphore Semaphore) { + + OSL_ASSERT(Semaphore != 0); /* abort in debug mode */ + if (Semaphore != 0) /* be tolerant in release mode */ + { + return (sem_trywait((sem_t*)Semaphore) == 0); + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_releaseSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseSemaphore(oslSemaphore Semaphore) { + + OSL_ASSERT(Semaphore != 0); /* abort in debug mode */ + + if (Semaphore != 0) /* be tolerant in release mode */ + { + return (sem_post((sem_t*)Semaphore) == 0); + } + + return sal_False; +} + +#else /* OSL_USE_SYS_V_SEMAPHORE */ + +/*******************************************************************************/ + +/* This is the SYS V private semaphore variant */ + +/* + Implemetation notes: + The void* represented by oslSemaphore is used + as a pointer to an osl_TSemImpl struct +*/ + + +#if defined(NETBSD) +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ + u_short *array; /* array for GETALL & SETALL */ +}; +#endif + +typedef struct _osl_TSemImpl +{ + int m_Id; + +} osl_TSemImpl; + +/*****************************************************************************/ +/* osl_createSemaphore */ +/*****************************************************************************/ +oslSemaphore SAL_CALL osl_createSemaphore(sal_uInt32 initialCount) +{ + union semun arg; + + oslSemaphore Semaphore; + osl_TSemImpl* pSem; + + Semaphore= malloc(sizeof(osl_TSemImpl)); + OSL_POSTCOND(Semaphore, "malloc failed\n"); /* ptr valid? */ + + pSem= (osl_TSemImpl*)Semaphore; + + + /* unnamed (private) semaphore */ + + pSem->m_Id= semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT); + + + /* create failed? */ + if (pSem->m_Id < 0) + { + OSL_TRACE("osl_createSemaphore failed (semget). Errno: %d; %s\n", + errno, + strerror(errno)); + + free(Semaphore); + return 0; + } + + /* set initial count */ + + arg.val= initialCount; + + if(semctl(pSem->m_Id, 0, SETVAL, arg) < 0) + { + OSL_TRACE("osl_createSemaphore failed (semctl(SETVAL)). Errno: %d; %s\n", + errno, + strerror(errno)); + + if(semctl(pSem->m_Id, 0, IPC_RMID, arg) < 0) + { + OSL_TRACE("semctl(IPC_RMID) failed. Errno: %d; %s\n", errno, strerror(errno)); + } + + free(Semaphore); + return 0; + } + + + return Semaphore; +} + +/*****************************************************************************/ +/* osl_destroySemaphore */ +/*****************************************************************************/ +void SAL_CALL osl_destroySemaphore(oslSemaphore Semaphore) { + + if(Semaphore) /* ptr valid? */ + { + union semun arg; + + osl_TSemImpl* pSem= (osl_TSemImpl*)Semaphore; + + if(semctl(pSem->m_Id, 0, IPC_RMID, arg) < 0) + + { + OSL_TRACE("osl_destroySemaphore failed. (semctl(IPC_RMID)). Errno: %d; %s\n", + errno, + strerror(errno)); + } + + free(Semaphore); + } +} + +/*****************************************************************************/ +/* osl_acquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_acquireSemaphore(oslSemaphore Semaphore) { + + /* abort in debug mode */ + OSL_PRECOND(Semaphore != 0, "Semaphore not created\n"); + + + if (Semaphore != 0) /* be tolerant in release mode */ + { + struct sembuf op; + osl_TSemImpl* pSem= (osl_TSemImpl*)Semaphore; + + op.sem_num= 0; + op.sem_op= -1; + op.sem_flg= SEM_UNDO; + + return semop(pSem->m_Id, &op, 1) >= 0; + + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_tryToAcquireSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_tryToAcquireSemaphore(oslSemaphore Semaphore) { + + /* abort in debug mode */ + OSL_PRECOND(Semaphore != 0, "Semaphore not created\n"); + + if (Semaphore != 0) /* be tolerant in release mode */ + { + struct sembuf op; + osl_TSemImpl* pSem= (osl_TSemImpl*)Semaphore; + + op.sem_num= 0; + op.sem_op= -1; + op.sem_flg= SEM_UNDO | IPC_NOWAIT; + + return semop(pSem->m_Id, &op, 1) >= 0; + } + + return sal_False; +} + +/*****************************************************************************/ +/* osl_releaseSemaphore */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_releaseSemaphore(oslSemaphore Semaphore) +{ + + /* abort in debug mode */ + OSL_PRECOND(Semaphore != 0, "Semaphore not created\n"); + + if (Semaphore != 0) /* be tolerant in release mode */ + { + struct sembuf op; + osl_TSemImpl* pSem= (osl_TSemImpl*)Semaphore; + + op.sem_num= 0; + op.sem_op= 1; + op.sem_flg= SEM_UNDO; + + return semop(pSem->m_Id, &op, 1) >= 0; + } + + return sal_False; +} + +#endif /* OSL_USE_SYS_V_SEMAPHORE */ + diff --git a/sal/osl/unx/signal.c b/sal/osl/unx/signal.c new file mode 100644 index 000000000000..5563375d9567 --- /dev/null +++ b/sal/osl/unx/signal.c @@ -0,0 +1,1093 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/* system headers */ +#include "system.h" + +#define MAX_STACK_FRAMES 256 + +#if defined( MACOSX ) + +#if defined( INTEL ) +#include "backtrace.h" +#define INCLUDE_BACKTRACE +#define STACKTYPE "MacOsX_X86" +#endif /* INTEL */ + +#endif /* MACOSX */ + +#ifdef LINUX +#include <execinfo.h> +#include <link.h> +#define INCLUDE_BACKTRACE +#define STACKTYPE "Linux" +#endif + +#ifdef SOLARIS + +#include "backtrace.h" +#define INCLUDE_BACKTRACE + +#if defined( SPARC ) +#define STACKTYPE "Solaris_Sparc" +#elif defined( INTEL ) +#define STACKTYPE "Solaris_X86" +#else +#define STACKTYPE "Solaris_Unknown" +#endif + +#endif /* defined SOLARIS */ + +#include <osl/diagnose.h> +#include <osl/mutex.h> +#include <osl/signal.h> +#include <osl/process.h> +#include <osl/thread.h> +#include <rtl/bootstrap.h> +#include <rtl/digest.h> + +#include "file_path_helper.h" + +#define ACT_IGNORE 1 +#define ACT_EXIT 2 +#define ACT_SYSTEM 3 +#define ACT_HIDE 4 +#ifdef SAL_ENABLE_CRASH_REPORT +# define ACT_ABORT 5 +#else +# define ACT_ABORT ACT_SYSTEM +#endif + +#define MAX_PATH_LEN 2048 + +typedef struct _oslSignalHandlerImpl +{ + oslSignalHandlerFunction Handler; + void* pData; + struct _oslSignalHandlerImpl* pNext; +} oslSignalHandlerImpl; + +static struct SignalAction +{ + int Signal; + int Action; + void (*Handler)(int); +} Signals[] = +{ + { SIGHUP, ACT_IGNORE, NULL }, /* hangup */ + { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */ + { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */ + { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */ +/* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/ + { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */ +#if ( SIGIOT != SIGABRT ) + { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */ +#endif + { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */ +#ifdef SIGEMT + { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */ +/* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/ +/* SIGEMT may also be used by the profiler - so it is probably not a good +plan to have the new handler use this signal*/ +#endif + { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */ + { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */ + { SIGBUS, ACT_ABORT, NULL }, /* bus error */ + { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */ +#ifdef SIGSYS + { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */ +#endif + { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */ + { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */ + { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */ + { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */ + { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */ + { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */ +#ifdef SIGPWR + { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */ +#endif + { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */ + { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */ +#ifdef SIGPOLL + { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occured */ +#endif + { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */ + { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */ + { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */ + { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */ + { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */ + { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */ + { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */ +/*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do +not get taken by the new handler - the new handler does not pass on context +information which causes 'collect' to crash. This is a way of avoiding +what looks like a bug in the new handler*/ + { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */ + { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */ +}; +const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction); + +static sal_Bool bErrorReportingEnabled = sal_True; +static sal_Bool bInitSignal = sal_False; +static oslMutex SignalListMutex; +static oslSignalHandlerImpl* SignalList; +static sal_Bool bDoHardKill = sal_False; +static sal_Bool bSetSEGVHandler = sal_False; +static sal_Bool bSetWINCHHandler = sal_False; +static sal_Bool bSetILLHandler = sal_False; + +static void SignalHandlerFunction(int); + +static void getExecutableName_Impl (rtl_String ** ppstrProgName) +{ + rtl_uString * ustrProgFile = 0; + osl_getExecutableFile (&ustrProgFile); + if (ustrProgFile) + { + rtl_uString * ustrProgName = 0; + osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName); + if (ustrProgName != 0) + { + rtl_uString2String ( + ppstrProgName, + rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS); + rtl_uString_release (ustrProgName); + } + rtl_uString_release (ustrProgFile); + } +} + +static sal_Bool is_soffice_Impl (void) +{ + sal_Int32 idx = -1; + rtl_String * strProgName = 0; + + getExecutableName_Impl (&strProgName); + if (strProgName) + { + idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice"); + rtl_string_release (strProgName); + } + return (idx != -1); +} + +static sal_Bool InitSignal() +{ + int i; + struct sigaction act; + struct sigaction oact; + sigset_t unset; + + if (is_soffice_Impl()) + { + sal_uInt32 argi; + sal_uInt32 argc; + rtl_uString *ustrCommandArg = 0; + + argc = osl_getCommandArgCount(); + for ( argi = 0; argi < argc; argi++ ) + { + if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg)) + { + if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean")) + { + bDoHardKill = sal_True; + break; + } + } + } + if (ustrCommandArg) + { + rtl_uString_release (ustrCommandArg); + ustrCommandArg = 0; + } + + // WORKAROUND FOR SEGV HANDLER CONFLICT + // + // the java jit needs SIGSEGV for proper work + // and we need SIGSEGV for the office crashguard + // + // TEMPORARY SOLUTION: + // the office sets the signal handler during startup + // java can than overwrite it, if needed + bSetSEGVHandler = sal_True; + + // WORKAROUND FOR WINCH HANDLER (SEE ABOVE) + bSetWINCHHandler = sal_True; + + // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE) + bSetILLHandler = sal_True; + } + + SignalListMutex = osl_createMutex(); + + act.sa_handler = SignalHandlerFunction; + act.sa_flags = SA_RESTART; + + sigfillset(&(act.sa_mask)); + + /* Initialize the rest of the signals */ + for (i = 0; i < NoSignals; i++) + { + /* hack: stomcatd is attaching JavaVM wich dont work with an sigaction(SEGV) */ + if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV) + && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH) + && (bSetILLHandler || Signals[i].Signal != SIGILL)) + { + if (Signals[i].Action != ACT_SYSTEM) + { + if (Signals[i].Action == ACT_HIDE) + { + struct sigaction ign; + + ign.sa_handler = SIG_IGN; + ign.sa_flags = 0; + sigemptyset(&ign.sa_mask); + + if (sigaction(Signals[i].Signal, &ign, &oact) == 0) + Signals[i].Handler = oact.sa_handler; + else + Signals[i].Handler = SIG_DFL; + } + else + if (sigaction(Signals[i].Signal, &act, &oact) == 0) + Signals[i].Handler = oact.sa_handler; + else + Signals[i].Handler = SIG_DFL; + } + } + } + + /* Clear signal mask inherited from parent process (on Mac OS X, upon a + crash soffice re-execs itself from within the signal handler, so the + second soffice would have the guilty signal blocked and would freeze upon + encountering a similar crash again): */ + if (sigemptyset(&unset) < 0 || + pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0) + { + OSL_TRACE("sigemptyset or pthread_sigmask failed"); + } + + return sal_True; +} + +static sal_Bool DeInitSignal() +{ + int i; + struct sigaction act; + + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + + /* Initialize the rest of the signals */ + for (i = NoSignals - 1; i >= 0; i--) + if (Signals[i].Action != ACT_SYSTEM) + { + act.sa_handler = Signals[i].Handler; + + sigaction(Signals[i].Signal, &act, NULL); + } + + osl_destroyMutex(SignalListMutex); + + return sal_False; +} + +#if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE) + +/*****************************************************************************/ +/* Generate MD5 checksum */ +/*****************************************************************************/ + +static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen ) +{ + sal_uInt32 nBytesProcessed = 0; + + FILE *fp = fopen( filename, "r" ); + + if ( fp ) + { + rtlDigest digest = rtl_digest_createMD5(); + + if ( digest ) + { + size_t nBytesRead; + sal_uInt8 buffer[4096]; + rtlDigestError error = rtl_Digest_E_None; + + while ( rtl_Digest_E_None == error && + 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) ) + { + error = rtl_digest_updateMD5( digest, buffer, nBytesRead ); + nBytesProcessed += nBytesRead; + } + + if ( rtl_Digest_E_None == error ) + { + error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen ); + } + + if ( rtl_Digest_E_None != error ) + nBytesProcessed = 0; + + rtl_digest_destroyMD5( digest ); + } + + fclose( fp ); + } + + return nBytesProcessed; +} + +/*****************************************************************************/ +/* Call crash reporter */ +/*****************************************************************************/ + +/* Helper function to encode and write a string to a stream */ + +static int fputs_xml( const char *string, FILE *stream ) +{ + int result = 0; + + while ( result >= 0 && *string ) + { + switch( *string ) + { + case '&': + result = fputs( "&", stream ); + break; + case '<': + result = fputs( "<", stream ); + break; + case '>': + result = fputs( ">", stream ); + break; + default: + result = fputc( *string, stream ); + break; + } + + string++; + } + + return result; +} +#endif + +/* Create intermediate files and run crash reporter */ + +#define REPORTENV_PARAM "-crashreportenv:" + +#if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \ + defined LINUX + +typedef struct +{ + const char *name; + ElfW(Off) offset; +} dynamic_entry; + +static int +callback(struct dl_phdr_info *info, size_t size, void *data) +{ + const ElfW(Phdr) *pDynamic = NULL; + + if (size == sizeof(struct dl_phdr_info)) + { + int i; + for (i = 0; i < info->dlpi_phnum; ++i) + { + if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) + { + pDynamic = &(info->dlpi_phdr[i]); + break; + } + } + } + + if (pDynamic) + { + char buffer[100]; + int len; + char exe[PATH_MAX]; + const char *dsoname = info->dlpi_name; + + dynamic_entry* entry = (dynamic_entry*)data; + + if (strcmp(dsoname, "") == 0) + { + snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid()); + if ((len = readlink(buffer, exe, PATH_MAX)) != -1) + { + exe[len] = '\0'; + dsoname = exe; + } + } + + if (strcmp(dsoname, entry->name) == 0) + { + entry->offset = pDynamic->p_offset; + return 1; + } + } + return 0; +} + +/* Get the location of the .dynamic section offset for the given elf file. + * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo + * + * We want to know this value so that if the binaries have been modifed + * by prelink then we can still process the call stack on server side + * by comparing this value to that of an "un-prelinked but known to be + * otherwise equivalent" version of those binaries and adjust the call + * stack addresses by the differences between .dynamic addresses so as + * to be able to map the prelinked addresses back to the unprelinked + * addresses + * + * cmc@openoffice.org + */ +static ElfW(Off) +dynamic_section_offset(const char *name) +{ + dynamic_entry entry; + + entry.name = name; + entry.offset = 0; + + dl_iterate_phdr(callback, &entry); + + return entry.offset; +} +#endif + +static int ReportCrash( int Signal ) +{ +#ifdef SAL_ENABLE_CRASH_REPORT + static sal_Bool bCrashReporterExecuted = sal_False; + sal_Bool bAutoCrashReport = sal_False; + + sal_uInt32 argi; + sal_uInt32 argc; + rtl_uString *ustrCommandArg = NULL; + + if ( !bErrorReportingEnabled ) + return -1; + + argc = osl_getCommandArgCount(); + + for ( argi = 0; argi < argc; argi++ ) + { + if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) ) + { + if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-nocrashreport" ) ) + { + rtl_uString_release( ustrCommandArg ); + return -1; + } + else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-autocrashreport" ) ) + { + bAutoCrashReport = sal_True; + } + else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( + rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ), + REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) + ) + { + rtl_uString *ustrEnvironment = NULL; + rtl_String *strEnv = NULL; + + rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) ); + + if ( ustrEnvironment ) + { + rtl_uString2String( + &strEnv, + rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ), + osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS + ); + + if ( strEnv ) + { + putenv( rtl_string_getStr( strEnv ) ); + rtl_string_release( strEnv ); + } + + rtl_uString_release( ustrEnvironment ); + } + + } + + } + } + + if ( ustrCommandArg ) + rtl_uString_release( ustrCommandArg ); + + if ( !bCrashReporterExecuted ) + { + int i; + /* struct sigaction act; */ + + for (i = 0; i < NoSignals; i++) + { + if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT ) + { + int ret; + char szShellCmd[512] = { '\0' }; + char *pXMLTempName = NULL; + char *pStackTempName = NULL; + char *pChecksumTempName = NULL; + +#ifdef INCLUDE_BACKTRACE + char szXMLTempNameBuffer[L_tmpnam]; + char szChecksumTempNameBuffer[L_tmpnam]; + char szStackTempNameBuffer[L_tmpnam]; + + void *stackframes[MAX_STACK_FRAMES]; + int iFrame; + int nFrames = backtrace( stackframes, sizeof(stackframes)/sizeof(stackframes[0])); + + FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL; + int fdxml, fdstk, fdchksum; + + strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) ); + strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) ); + + strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) ); + strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) ); + + strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) ); + strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) ); + + fdxml = mkstemp(szXMLTempNameBuffer); + fdstk = mkstemp(szStackTempNameBuffer); + fdchksum = mkstemp(szChecksumTempNameBuffer); + + xmlout = fdopen( fdxml , "w" ); + stackout = fdopen( fdstk , "w" ); + checksumout = fdopen( fdchksum, "w" ); + + pXMLTempName = szXMLTempNameBuffer; + pStackTempName = szStackTempNameBuffer; + pChecksumTempName = szChecksumTempNameBuffer; + + + if ( xmlout && stackout && checksumout ) + { + fprintf( xmlout, "<errormail:Stack type=\"%s\">\n", STACKTYPE ); + + fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\n" ); + + for ( iFrame = 0; iFrame < nFrames; iFrame++ ) + { + Dl_info dl_info; + + fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":", + SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) ); + + fprintf( xmlout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"", + iFrame, + SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) + ); + + memset( &dl_info, 0, sizeof(dl_info) ); + + /* dladdr may fail */ + if ( dladdr( stackframes[iFrame], &dl_info) ) + { + const char *dli_fname = NULL; + char *dli_fdir = NULL; + char szDirectory[PATH_MAX]; + char szCanonicDirectory[PATH_MAX]; + + /* Don't expect that dladdr filled all members of dl_info */ + + dli_fname = dl_info.dli_fname ? strrchr( dl_info.dli_fname, '/' ) : NULL; + if ( dli_fname ) + { + ++dli_fname; + memcpy( szDirectory, dl_info.dli_fname, dli_fname - dl_info.dli_fname ); + szDirectory[dli_fname - dl_info.dli_fname] = 0; + + dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory; + + if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' ) + strcat( dli_fdir, "/" ); + } + else + dli_fname = dl_info.dli_fname; + + /* create checksum of library on stack */ + if ( dli_fname ) + { + sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5]; + + sal_uInt32 nBytesProcessed = calc_md5_checksum( + dl_info.dli_fname, checksum, sizeof(checksum) ); + if ( nBytesProcessed ) + { + int j; + + fprintf( checksumout, "<errormail:Checksum sum=\"0x" ); + for ( j = 0; j < 16; fprintf( checksumout, "%02X", checksum[j++] ) ); + fprintf( checksumout, + "\" bytes=\"%lu\" file=\"%s\"/>\n", + SAL_INT_CAST( + unsigned long, nBytesProcessed), + dli_fname ); + } + } + + if ( dl_info.dli_fbase && dl_info.dli_fname ) + { +#ifdef LINUX + ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname); + fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset); +#endif + + fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x", + dl_info.dli_fname, + (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase + ); + + fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase ); + if ( dli_fname ) + fprintf( xmlout, " name=\"%s\"", dli_fname ); + + if ( dli_fdir ) + fprintf( xmlout, " path=\"%s\"", dli_fdir ); + +#ifdef LINUX + fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset ); +#endif + } + else + fprintf( stackout, " ????????" ); + + if ( dl_info.dli_sname && dl_info.dli_saddr ) + { + fputs( " (", stackout ); + fputs_xml( dl_info.dli_sname, stackout ); + fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)", + (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr ); + + fputs( " ordinal=\"", xmlout ); + fputs_xml( dl_info.dli_sname, xmlout ); + fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"", + (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr ); + } + + } + else /* dladdr failed */ + { + fprintf( stackout, " ????????" ); + } + + fprintf( stackout, "\n" ); + fprintf( xmlout, "/>\n" ); + + } + + fprintf( xmlout, "</errormail:Stack>\n" ); + fprintf( checksumout, "</errormail:Checksums>\n" ); + } + else + { + pXMLTempName = NULL; + pStackTempName = NULL; + pChecksumTempName = NULL; + } + + if ( stackout ) + fclose( stackout ); + if ( xmlout ) + fclose( xmlout ); + if ( checksumout ) + fclose( checksumout ); + + if ( pXMLTempName && pChecksumTempName && pStackTempName ) +#endif /* INCLUDE_BACKTRACE */ + { + rtl_uString * crashrep_url = NULL; + rtl_uString * crashrep_path = NULL; + rtl_String * crashrep_path_system = NULL; + rtl_string2UString( + &crashrep_url, + RTL_CONSTASCII_USTRINGPARAM( + "$BRAND_BASE_DIR/program/crashrep"), + OSTRING_TO_OUSTRING_CVTFLAGS); + rtl_bootstrap_expandMacros(&crashrep_url); + osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path); + rtl_uString2String( + &crashrep_path_system, + rtl_uString_getStr(crashrep_path), + rtl_uString_getLength(crashrep_path), + osl_getThreadTextEncoding(), + (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR + | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)); + rtl_uString_release(crashrep_url); + rtl_uString_release(crashrep_path); +#if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX) + snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]), + "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), + Signal, + pXMLTempName, + pChecksumTempName, + pStackTempName, + bAutoCrashReport ? " -send" : "" ); +#elif defined INCLUDE_BACKTRACE && defined SOLARIS + snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]), + "%s -p %d -s %d -xml %s -chksum %s -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), + Signal, + pXMLTempName, + pChecksumTempName, + bAutoCrashReport ? " -send" : "" ); +#else + snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]), + "%s -p %d -s %d -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), Signal, bAutoCrashReport ? " -send" : "" ); +#endif + rtl_string_release(crashrep_path_system); + } + + ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd ); + + if ( pXMLTempName ) + unlink( pXMLTempName ); + + if ( pStackTempName ) + unlink( pStackTempName ); + + if ( pChecksumTempName ) + unlink( pChecksumTempName ); + + if ( -1 != ret ) + { + bCrashReporterExecuted = sal_True; + return 1; + } + else + return -1; + + } + } + + return 0; + } + + return 1; +#else /* defined SAL_ENABLE_CRASH_REPORT */ + /* the utility crash_report is not build, so do the same as when + the option -nocrashreport is used */ + (void) Signal; // avoid warnings + return -1; +#endif /* defined SAL_ENABLE_CRASH_REPORT */ +} + +static void PrintStack( int sig ) +{ +#if ! defined(MACOSX) || defined(INCLUDE_BACKTRACE) + void *buffer[MAX_STACK_FRAMES]; + int size = backtrace( buffer, sizeof(buffer) / sizeof(buffer[0]) ); +#endif + + fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig ); + +#if defined(MACOSX) && ! defined(INCLUDE_BACKTRACE) + fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" ); +#else + if ( size > 0 ) + { + fputs( "Stack:\n", stderr ); + backtrace_symbols_fd( buffer, size, fileno(stderr) ); + } +#endif +} + +static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) +{ + oslSignalHandlerImpl* pHandler = SignalList; + oslSignalAction Action = osl_Signal_ActCallNextHdl; + + while (pHandler != NULL) + { + if ((Action = pHandler->Handler(pHandler->pData, pInfo)) + != osl_Signal_ActCallNextHdl) + break; + + pHandler = pHandler->pNext; + } + + return Action; +} + +void CallSystemHandler(int Signal) +{ + int i; + struct sigaction act; + + for (i = 0; i < NoSignals; i++) + { + if (Signals[i].Signal == Signal) + break; + } + + if (i < NoSignals) + { + if ((Signals[i].Handler == NULL) || + (Signals[i].Handler == SIG_DFL) || + (Signals[i].Handler == SIG_IGN) || + (Signals[i].Handler == SIG_ERR)) + { + switch (Signals[i].Action) + { + case ACT_EXIT: /* terminate */ + /* prevent dumping core on exit() */ + _exit(255); + break; + + case ACT_ABORT: /* terminate witch core dump */ + ReportCrash( Signal ); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + sigaction(SIGABRT, &act, NULL); + PrintStack( Signal ); + abort(); + break; + + case ACT_IGNORE: /* ignore */ + break; + + default: /* should never happen */ + OSL_ASSERT(0); + } + } + else + (*Signals[i].Handler)(Signal); + } +} + + +/*****************************************************************************/ +/* SignalHandlerFunction */ +/*****************************************************************************/ +void SignalHandlerFunction(int Signal) +{ + oslSignalInfo Info; + struct sigaction act; + + Info.UserSignal = Signal; + Info.UserData = NULL; + + switch (Signal) + { + case SIGBUS: + case SIGILL: + case SIGSEGV: + case SIGIOT: +#if ( SIGIOT != SIGABRT ) + case SIGABRT: +#endif + Info.Signal = osl_Signal_AccessViolation; + break; + + case -1: + Info.Signal = osl_Signal_IntegerDivideByZero; + break; + + case SIGFPE: + Info.Signal = osl_Signal_FloatDivideByZero; + break; + + case SIGINT: + case SIGTERM: + case SIGQUIT: + case SIGHUP: + Info.Signal = osl_Signal_Terminate; + break; + + default: + Info.Signal = osl_Signal_System; + break; + } + + ReportCrash( Signal ); + + /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation)) + _exit(255); + /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + + + switch (CallSignalHandler(&Info)) + { + case osl_Signal_ActCallNextHdl: + CallSystemHandler(Signal); + break; + + case osl_Signal_ActAbortApp: + ReportCrash( Signal ); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + sigaction(SIGABRT, &act, NULL); + PrintStack( Signal ); + abort(); + break; + + case osl_Signal_ActKillApp: + /* prevent dumping core on exit() */ + _exit(255); + break; + default: + break; + } +} + +/*****************************************************************************/ +/* osl_addSignalHandler */ +/*****************************************************************************/ +oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) +{ + oslSignalHandlerImpl* pHandler; + + OSL_ASSERT(Handler != NULL); + if ( Handler == 0 ) + { + return 0; + } + + if (! bInitSignal) + bInitSignal = InitSignal(); + + pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl)); + + if (pHandler != NULL) + { + pHandler->Handler = Handler; + pHandler->pData = pData; + + osl_acquireMutex(SignalListMutex); + + pHandler->pNext = SignalList; + SignalList = pHandler; + + osl_releaseMutex(SignalListMutex); + + return (pHandler); + } + + return (NULL); +} + +/*****************************************************************************/ +/* osl_removeSignalHandler */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) +{ + oslSignalHandlerImpl *pHandler, *pPrevious = NULL; + + OSL_ASSERT(Handler != NULL); + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + pHandler = SignalList; + + while (pHandler != NULL) + { + if (pHandler == Handler) + { + if (pPrevious) + pPrevious->pNext = pHandler->pNext; + else + SignalList = pHandler->pNext; + + osl_releaseMutex(SignalListMutex); + + if (SignalList == NULL) + bInitSignal = DeInitSignal(); + + free(pHandler); + + return (sal_True); + } + + pPrevious = pHandler; + pHandler = pHandler->pNext; + } + + osl_releaseMutex(SignalListMutex); + + return (sal_False); +} + +/*****************************************************************************/ +/* osl_raiseSignal */ +/*****************************************************************************/ +oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) +{ + oslSignalInfo Info; + oslSignalAction Action; + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + Info.Signal = osl_Signal_User; + Info.UserSignal = UserSignal; + Info.UserData = UserData; + + Action = CallSignalHandler(&Info); + + osl_releaseMutex(SignalListMutex); + + return (Action); +} + +/*****************************************************************************/ +/* osl_setErrorReporting */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) +{ + sal_Bool bOld = bErrorReportingEnabled; + bErrorReportingEnabled = bEnable; + + return bOld; +} diff --git a/sal/osl/unx/socket.c b/sal/osl/unx/socket.c new file mode 100644 index 000000000000..c8faf6c028f5 --- /dev/null +++ b/sal/osl/unx/socket.c @@ -0,0 +1,3062 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#include <osl/socket.h> +#include <osl/diagnose.h> +#include <osl/mutex.h> +#include <osl/signal.h> + +#include <rtl/alloc.h> + +#include <ctype.h> +#include <sal/types.h> + +#include "sockimpl.h" + + +/* defines for poll */ +#ifdef HAVE_POLL_H +#undef HAVE_POLL_H +#endif + +#if defined(LINUX) || defined(NETBSD) || defined ( FREEBSD ) || defined (MACOSX) +#include <sys/poll.h> +#define HAVE_POLL_H +#endif /* HAVE_POLL_H */ + +#if defined(SOLARIS) +#include <poll.h> +#define HAVE_POLL_H +#endif /* SOLARIS */ + +#ifndef HAVE_POLL_H +#define POLLIN 0x0001 +#define POLLOUT 0x0002 +#define POLLPRI 0x0004 +#endif /* HAVE_POLL_H */ + + +/* defines for shutdown */ +#define SD_RECEIVE 0 +#define SD_SEND 1 +#define SD_BOTH 2 + + +/* + oslSocketAddr is a pointer to a Berkeley struct sockaddr. + I refrained from using sockaddr_in because of possible further + extensions of this socket-interface (IP-NG?). + The intention was to hide all Berkeley data-structures from + direct access past the osl-interface. + + The current implementation is internet (IP) centered. All + the constructor-functions (osl_create...) take parameters + that will probably make sense only in the IP-environment + (e.g. because of using the dotted-address-format). + + If the interface will be extended to host other protocol- + families, I expect no externally visible changes in the + existing functions. You'll probably need only new + constructor-functions who take the different address + formats into consideration (maybe a long dotted address + or whatever). +*/ + +/* _Note_ that I rely on the fact that oslSocketAddr and struct sockaddr */ +/* are the same! I don't like it very much but see no other easy way to */ +/* conceal the struct sockaddr from the eyes of the user. */ + + +#define OSL_INVALID_SOCKET -1 +#define OSL_SOCKET_ERROR -1 + + +/* Buffer size for gethostbyname */ +#define MAX_HOSTBUFFER_SIZE 2048 + +/*****************************************************************************/ +/* enum oslAddrFamily */ +/*****************************************************************************/ + +/* map */ +static unsigned long FamilyMap[]= { + AF_INET, /* osl_Socket_FamilyInet */ + AF_IPX, /* osl_Socket_FamilyIpx */ + 0 /* osl_Socket_FamilyInvalid */ +}; + +/* reverse map */ +static oslAddrFamily osl_AddrFamilyFromNative(sal_uInt32 nativeType) +{ + oslAddrFamily i= (oslAddrFamily)0; + + while(i != osl_Socket_FamilyInvalid) + { + if(FamilyMap[i] == nativeType) + return i; + i = (oslAddrFamily) ( i + 1 ); + } + + return i; +} + +/* macros */ +#define FAMILY_FROM_NATIVE(y) osl_AddrFamilyFromNative(y) +#define FAMILY_TO_NATIVE(x) (short)FamilyMap[x] + +/*****************************************************************************/ +/* enum oslProtocol */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 ProtocolMap[]= { + 0, /* osl_Socket_ProtocolIp */ + NSPROTO_IPX, /* osl_Socket_ProtocolIpx */ + NSPROTO_SPX, /* osl_Socket_ProtocolSpx */ + NSPROTO_SPXII, /* osl_Socket_ProtocolSpxII */ + 0 /* osl_Socket_ProtocolInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslProtocol osl_ProtocolFromNative(sal_uInt32 nativeType) +{ + oslProtocol i= (oslProtocol)0; + + while(i != osl_Socket_ProtocolInvalid) + { + if(ProtocolMap[i] == nativeType) + return i; + i = (oslProtocol) ( i + 1); + } + + return i; +} +*/ + +/* macros */ +#define PROTOCOL_FROM_NATIVE(y) osl_ProtocolFromNative(y) +#define PROTOCOL_TO_NATIVE(x) ProtocolMap[x] + + +/*****************************************************************************/ +/* enum oslSocketType */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 TypeMap[]= { + SOCK_STREAM, /* osl_Socket_TypeStream */ + SOCK_DGRAM, /* osl_Socket_TypeDgram */ + SOCK_RAW, /* osl_Socket_TypeRaw */ + SOCK_RDM, /* osl_Socket_TypeRdm */ + SOCK_SEQPACKET, /* osl_Socket_TypeSeqPacket */ + 0 /* osl_Socket_TypeInvalid */ +}; + +/* reverse map */ +static oslSocketType osl_SocketTypeFromNative(sal_uInt32 nativeType) +{ + oslSocketType i= (oslSocketType)0; + + while(i != osl_Socket_TypeInvalid) + { + if(TypeMap[i] == nativeType) + return i; + i = (oslSocketType)(i + 1); + } + + return i; +} + +/* macros */ +#define TYPE_TO_NATIVE(x) TypeMap[x] +#define TYPE_FROM_NATIVE(y) osl_SocketTypeFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketOption */ +/*****************************************************************************/ + +/* map */ +static sal_uInt32 OptionMap[]= { + SO_DEBUG, /* osl_Socket_OptionDebug */ + SO_ACCEPTCONN, /* osl_Socket_OptionAcceptConn */ + SO_REUSEADDR, /* osl_Socket_OptionReuseAddr */ + SO_KEEPALIVE, /* osl_Socket_OptionKeepAlive */ + SO_DONTROUTE, /* osl_Socket_OptionDontRoute */ + SO_BROADCAST, /* osl_Socket_OptionBroadcast */ + SO_USELOOPBACK, /* osl_Socket_OptionUseLoopback */ + SO_LINGER, /* osl_Socket_OptionLinger */ + SO_OOBINLINE, /* osl_Socket_OptionOOBinLine */ + SO_SNDBUF, /* osl_Socket_OptionSndBuf */ + SO_RCVBUF, /* osl_Socket_OptionRcvBuf */ + SO_SNDLOWAT, /* osl_Socket_OptionSndLowat */ + SO_RCVLOWAT, /* osl_Socket_OptionRcvLowat */ + SO_SNDTIMEO, /* osl_Socket_OptionSndTimeo */ + SO_RCVTIMEO, /* osl_Socket_OptionRcvTimeo */ + SO_ERROR, /* osl_Socket_OptionError */ + SO_TYPE, /* osl_Socket_OptionType */ + TCP_NODELAY, /* osl_Socket_OptionTcpNoDelay */ + 0 /* osl_Socket_OptionInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketOption osl_SocketOptionFromNative(sal_uInt32 nativeType) +{ + oslSocketOption i= (oslSocketOption)0; + + while(i != osl_Socket_OptionInvalid) + { + if(OptionMap[i] == nativeType) + return i; + i = (oslSocketOption) ( i + 1 ); + } + + return i; +} +*/ +/* macros */ +#define OPTION_TO_NATIVE(x) OptionMap[x] +#define OPTION_FROM_NATIVE(y) osl_SocketOptionFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketOptionLevel */ +/*****************************************************************************/ + +static sal_uInt32 OptionLevelMap[]= { + SOL_SOCKET, /* osl_Socket_LevelSocket */ + IPPROTO_TCP, /* osl_Socket_LevelTcp */ + 0 /* osl_Socket_LevelInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketOptionLevel osl_SocketOptionLevelFromNative(sal_uInt32 nativeType) +{ + oslSocketOptionLevel i= (oslSocketOptionLevel)0; + + while(i != osl_Socket_LevelInvalid) + { + if(OptionLevelMap[i] == nativeType) + return i; + i = (oslSocketOptionLevel) ( i + 1 ); + } + + return i; +} +*/ +/* macros */ +#define OPTION_LEVEL_TO_NATIVE(x) OptionLevelMap[x] +#define OPTION_LEVEL_FROM_NATIVE(y) osl_SocketOptionLevelFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketMsgFlag */ +/*****************************************************************************/ + +static sal_uInt32 SocketMsgFlagMap[]= { + 0, /* osl_Socket_MsgNormal */ + MSG_OOB, /* osl_Socket_MsgOOB */ + MSG_PEEK, /* osl_Socket_MsgPeek */ + MSG_DONTROUTE, /* osl_Socket_MsgDontRoute */ + MSG_MAXIOVLEN, /* osl_Socket_MsgMaxIOVLen */ + 0 /* osl_Socket_MsgInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketMsgFlag osl_SocketMsgFlagFromNative(sal_uInt32 nativeType) +{ + oslSocketMsgFlag i= (oslSocketMsgFlag)0; + + while(i != osl_Socket_MsgInvalid) + { + if(SocketMsgFlagMap[i] == nativeType) + return i; + i = (oslSocketMsgFlag) ( i + 1 ); + } + + return i; +} +*/ + +/* macros */ +#define MSG_FLAG_TO_NATIVE(x) SocketMsgFlagMap[x] +#define MSG_FLAG_FROM_NATIVE(y) osl_SocketMsgFlagFromNative(y) + + +/*****************************************************************************/ +/* enum oslSocketDirection */ +/*****************************************************************************/ + +static sal_uInt32 SocketDirection[]= { + SD_RECEIVE, /* osl_Socket_DirRead */ + SD_SEND, /* osl_Socket_DirWrite */ + SD_BOTH, /* osl_Socket_DirReadWrite */ + 0 /* osl_Socket_DirInvalid */ +}; + +/* reverse map */ +/* mfe: NOT USED +static oslSocketDirection osl_SocketDirectionFromNative(sal_uInt32 nativeType) +{ + oslSocketDirection i= (oslSocketDirection)0; + + while(i != osl_Socket_DirInvalid) + { + if(SocketDirection[i] == nativeType) + return i; + i = (oslSocketDirection) ( i + 1 ); + } + + return i; +} +*/ + +/* macros */ +#define DIRECTION_TO_NATIVE(x) SocketDirection[x] +#define DIRECTION_FROM_NATIVE(y) osl_SocketDirectionFromNative(y) + +/*****************************************************************************/ +/* enum oslSocketError */ +/*****************************************************************************/ + +static struct +{ + int errcode; + oslSocketError error; +} SocketError[]= { + { 0, osl_Socket_E_None }, /* no error */ + { ENOTSOCK, osl_Socket_E_NotSocket }, /* Socket operation on non-socket */ + { EDESTADDRREQ, osl_Socket_E_DestAddrReq }, /* Destination address required */ + { EMSGSIZE, osl_Socket_E_MsgSize }, /* Message too long */ + { EPROTOTYPE, osl_Socket_E_Prototype }, /* Protocol wrong type for socket */ + { ENOPROTOOPT, osl_Socket_E_NoProtocol }, /* Protocol not available */ + { EPROTONOSUPPORT, osl_Socket_E_ProtocolNoSupport }, /* Protocol not supported */ + { ESOCKTNOSUPPORT, osl_Socket_E_TypeNoSupport }, /* Socket type not supported */ + { EOPNOTSUPP, osl_Socket_E_OpNotSupport }, /* Operation not supported on socket */ + { EPFNOSUPPORT, osl_Socket_E_PfNoSupport }, /* Protocol family not supported */ + { EAFNOSUPPORT, osl_Socket_E_AfNoSupport }, /* Address family not supported by */ + /* protocol family */ + { EADDRINUSE, osl_Socket_E_AddrInUse }, /* Address already in use */ + { EADDRNOTAVAIL, osl_Socket_E_AddrNotAvail }, /* Can't assign requested address */ + { ENETDOWN, osl_Socket_E_NetDown }, /* Network is down */ + { ENETUNREACH, osl_Socket_E_NetUnreachable }, /* Network is unreachable */ + { ENETRESET, osl_Socket_E_NetReset }, /* Network dropped connection because */ + /* of reset */ + { ECONNABORTED, osl_Socket_E_ConnAborted }, /* Software caused connection abort */ + { ECONNRESET, osl_Socket_E_ConnReset }, /* Connection reset by peer */ + { ENOBUFS, osl_Socket_E_NoBufferSpace }, /* No buffer space available */ + { EISCONN, osl_Socket_E_IsConnected }, /* Socket is already connected */ + { ENOTCONN, osl_Socket_E_NotConnected }, /* Socket is not connected */ + { ESHUTDOWN, osl_Socket_E_Shutdown }, /* Can't send after socket shutdown */ + { ETOOMANYREFS, osl_Socket_E_TooManyRefs }, /* Too many references: can't splice */ + { ETIMEDOUT, osl_Socket_E_TimedOut }, /* Connection timed out */ + { ECONNREFUSED, osl_Socket_E_ConnRefused }, /* Connection refused */ + { EHOSTDOWN, osl_Socket_E_HostDown }, /* Host is down */ + { EHOSTUNREACH, osl_Socket_E_HostUnreachable }, /* No route to host */ + { EWOULDBLOCK, osl_Socket_E_WouldBlock }, /* call would block on non-blocking socket */ + { EALREADY, osl_Socket_E_Already }, /* operation already in progress */ + { EINPROGRESS, osl_Socket_E_InProgress }, /* operation now in progress */ + { EAGAIN, osl_Socket_E_WouldBlock }, /* same as EWOULDBLOCK */ + { -1, osl_Socket_E_InvalidError } +}; + +/* map */ +/* mfe: NOT USED +static int osl_NativeFromSocketError(oslSocketError errorCode) +{ + int i = 0; + + while ((SocketError[i].error != osl_Socket_E_InvalidError) && + (SocketError[i].error != errorCode)) i++; + + return SocketError[i].errcode; +} +*/ + +/* reverse map */ +static oslSocketError osl_SocketErrorFromNative(int nativeType) +{ + int i = 0; + + while ((SocketError[i].error != osl_Socket_E_InvalidError) && + (SocketError[i].errcode != nativeType)) i++; + + return SocketError[i].error; +} + +/* macros */ +#define ERROR_TO_NATIVE(x) osl_NativeFromSocketError(x) +#define ERROR_FROM_NATIVE(y) osl_SocketErrorFromNative(y) + +/*****************************************************************************/ +/* local function prototypes */ +/*****************************************************************************/ + +oslSocketAddr SAL_CALL osl_psz_createInetSocketAddr ( + const sal_Char* pszDottedAddr, sal_Int32 Port); + +oslSocketAddr SAL_CALL osl_psz_createIpxSocketAddr ( + const sal_Char NetNumber[4], + const sal_Char NodeNumber[6], + sal_uInt32 SocketNumber); + +oslHostAddr SAL_CALL osl_psz_createHostAddr ( + const sal_Char *pszHostname, const oslSocketAddr Addr); + +oslHostAddr SAL_CALL osl_psz_createHostAddrByName ( + const sal_Char *pszHostname); + +const sal_Char* SAL_CALL osl_psz_getHostnameOfHostAddr ( + const oslHostAddr Addr); + +oslSocketResult SAL_CALL osl_psz_getLocalHostname ( + sal_Char *pBuffer, sal_uInt32 nBufLen); + +oslSocketAddr SAL_CALL osl_psz_resolveHostname ( + const sal_Char* pszHostname); + +sal_Int32 SAL_CALL osl_psz_getServicePort ( + const sal_Char* pszServicename, const sal_Char* pszProtocol); + +oslSocketResult SAL_CALL osl_psz_getHostnameOfSocketAddr ( + oslSocketAddr Addr, sal_Char *pBuffer, sal_uInt32 BufferSize); + +oslSocketResult SAL_CALL osl_psz_getDottedInetAddrOfSocketAddr ( + oslSocketAddr Addr, sal_Char *pBuffer, sal_uInt32 BufferSize); + +void SAL_CALL osl_psz_getLastSocketErrorDescription ( + oslSocket Socket, sal_Char* pBuffer, sal_uInt32 BufferSize); + +/*****************************************************************************/ +/* osl_create/destroy-SocketImpl */ +/*****************************************************************************/ + +#if OSL_DEBUG_LEVEL > 1 +static sal_uInt32 g_nSocketImpl = 0; +static sal_uInt32 g_nSocketAddr = 0; + +/* sorry, must be implemented otherwise */ +#if 0 +struct LeakWarning +{ + ~LeakWarning() + { + if( g_nSocketImpl ) + OSL_TRACE( "sal_socket: %d socket instances leak\n" , g_nSocketImpl ); + if( g_nSocketAddr ) + OSL_TRACE( "sal_socket: %d socket address instances leak\n" , g_nSocketAddr ); + } +}; +LeakWarning socketWarning; +#endif + +#endif /* OSL_DEBUG_LEVEL */ + + +oslSocket __osl_createSocketImpl(int Socket) +{ + oslSocket pSocket; + + pSocket = (oslSocket)calloc(1, sizeof(struct oslSocketImpl)); + + pSocket->m_Socket = Socket; + pSocket->m_nLastError = 0; + pSocket->m_CloseCallback = 0; + pSocket->m_CallbackArg = 0; + pSocket->m_nRefCount = 1; + +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_False; +#endif + +#if OSL_DEBUG_LEVEL > 1 + g_nSocketImpl ++; +#endif + return pSocket; +} + +void __osl_destroySocketImpl(oslSocket Socket) +{ + if ( Socket != NULL) + free((struct oslSocketImpl *) Socket); +#if OSL_DEBUG_LEVEL > 1 + g_nSocketImpl --; +#endif +} + +static oslSocketAddr __osl_createSocketAddr( ) +{ + oslSocketAddr pAddr = (oslSocketAddr) rtl_allocateZeroMemory( sizeof( struct oslSocketAddrImpl )); +#if OSL_DEBUG_LEVEL > 1 + g_nSocketAddr ++; +#endif + return pAddr; +} + +static oslSocketAddr __osl_createSocketAddrWithFamily( + oslAddrFamily family, sal_Int32 port, sal_uInt32 nAddr ) +{ + oslSocketAddr pAddr; + + OSL_ASSERT( family == osl_Socket_FamilyInet ); + + pAddr = __osl_createSocketAddr(); + switch( family ) + { + case osl_Socket_FamilyInet: + { + struct sockaddr_in* pInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + pInetAddr->sin_family = FAMILY_TO_NATIVE(osl_Socket_FamilyInet); + pInetAddr->sin_addr.s_addr = nAddr; + pInetAddr->sin_port = (sal_uInt16)(port&0xffff); + break; + } + default: + pAddr->m_sockaddr.sa_family = FAMILY_TO_NATIVE(family); + } + return pAddr; +} + +static oslSocketAddr __osl_createSocketAddrFromSystem( struct sockaddr *pSystemSockAddr ) +{ + oslSocketAddr pAddr = __osl_createSocketAddr(); + memcpy( &(pAddr->m_sockaddr), pSystemSockAddr, sizeof( struct sockaddr ) ); + return pAddr; +} + +static void __osl_destroySocketAddr( oslSocketAddr addr ) +{ +#if OSL_DEBUG_LEVEL > 1 + g_nSocketAddr --; +#endif + rtl_freeMemory( addr ); +} + +/*****************************************************************************/ +/* osl_createEmptySocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createEmptySocketAddr(oslAddrFamily Family) +{ + oslSocketAddr pAddr = 0; + + /* is it an internet-Addr? */ + if (Family == osl_Socket_FamilyInet) + { + pAddr = __osl_createSocketAddrWithFamily(Family, 0 , htonl(INADDR_ANY) ); + } + else + { + pAddr = __osl_createSocketAddrWithFamily( Family , 0 , 0 ); + } + + return pAddr; +} + +/*****************************************************************************/ +/* osl_copySocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_copySocketAddr(oslSocketAddr Addr) +{ + oslSocketAddr pCopy = 0; + if (Addr) + { + pCopy = __osl_createSocketAddr(); + + if (pCopy) + memcpy(&(pCopy->m_sockaddr),&(Addr->m_sockaddr), sizeof(struct sockaddr)); + } + return pCopy; +} + +/*****************************************************************************/ +/* osl_isEqualSocketAddr */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isEqualSocketAddr ( + oslSocketAddr Addr1, + oslSocketAddr Addr2) +{ + struct sockaddr* pAddr1= &(Addr1->m_sockaddr); + struct sockaddr* pAddr2= &(Addr2->m_sockaddr); + + OSL_ASSERT(pAddr1); + OSL_ASSERT(pAddr2); + + if (pAddr1->sa_family == pAddr2->sa_family) + { + switch (pAddr1->sa_family) + { + case AF_INET: + { + struct sockaddr_in* pInetAddr1= (struct sockaddr_in*)pAddr1; + struct sockaddr_in* pInetAddr2= (struct sockaddr_in*)pAddr2; + + if ((pInetAddr1->sin_family == pInetAddr2->sin_family) && + (pInetAddr1->sin_addr.s_addr == pInetAddr2->sin_addr.s_addr) && + (pInetAddr1->sin_port == pInetAddr2->sin_port)) + return (sal_True); + } + + default: + { + return (memcmp(pAddr1, Addr2, sizeof(struct sockaddr)) == 0); + } + } + } + + return (sal_False); +} + +/*****************************************************************************/ +/* osl_createInetBroadcastAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createInetBroadcastAddr ( + rtl_uString *strDottedAddr, + sal_Int32 Port) +{ + sal_uInt32 nAddr = OSL_INADDR_NONE; + oslSocketAddr pAddr; + + if (strDottedAddr && strDottedAddr->length) + { + /* Dotted host address for limited broadcast */ + rtl_String *pDottedAddr = NULL; + + rtl_uString2String ( + &pDottedAddr, strDottedAddr->buffer, strDottedAddr->length, + RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + + nAddr = inet_addr (pDottedAddr->buffer); + rtl_string_release (pDottedAddr); + } + + if (nAddr != OSL_INADDR_NONE) + { + /* Limited broadcast */ + nAddr = ntohl(nAddr); + if (IN_CLASSA(nAddr)) + { + nAddr &= IN_CLASSA_NET; + nAddr |= IN_CLASSA_HOST; + } + else if (IN_CLASSB(nAddr)) + { + nAddr &= IN_CLASSB_NET; + nAddr |= IN_CLASSB_HOST; + } + else if (IN_CLASSC(nAddr)) + { + nAddr &= IN_CLASSC_NET; + nAddr |= IN_CLASSC_HOST; + } + else + { + /* No broadcast in class D */ + return ((oslSocketAddr)NULL); + } + nAddr = htonl(nAddr); + } + + pAddr = __osl_createSocketAddrWithFamily( osl_Socket_FamilyInet, htons(Port), nAddr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_createInetSocketAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_createInetSocketAddr ( + rtl_uString *ustrDottedAddr, + sal_Int32 Port) +{ + rtl_String* strDottedAddr=0; + oslSocketAddr Addr; + sal_Char* pszDottedAddr=0; + + if ( ustrDottedAddr != 0 ) + { + rtl_uString2String( &strDottedAddr, + rtl_uString_getStr(ustrDottedAddr), + rtl_uString_getLength(ustrDottedAddr), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS); + pszDottedAddr = rtl_string_getStr(strDottedAddr); + } + + + Addr = osl_psz_createInetSocketAddr(pszDottedAddr, Port); + + if ( strDottedAddr != 0 ) + { + rtl_string_release(strDottedAddr); + } + + return Addr; +} + +oslSocketAddr SAL_CALL osl_psz_createInetSocketAddr ( + const sal_Char* pszDottedAddr, + sal_Int32 Port) +{ + oslSocketAddr pAddr = 0; + sal_Int32 Addr = inet_addr(pszDottedAddr); + if(Addr != -1) + { + /* valid dotted addr */ + pAddr = __osl_createSocketAddrWithFamily( osl_Socket_FamilyInet, htons(Port) , Addr ); + } + return pAddr; +} + +/*****************************************************************************/ +/* osl_setAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_setAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence *pByteSeq ) +{ + oslSocketResult res = osl_Socket_Error; + + OSL_ASSERT( pAddr ); + OSL_ASSERT( pByteSeq ); + + if( pAddr && pByteSeq ) + { + struct sockaddr_in * pSystemInetAddr; + + OSL_ASSERT( pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE( osl_Socket_FamilyInet ) ); + OSL_ASSERT( pByteSeq->nElements == 4 ); + + pSystemInetAddr = (struct sockaddr_in * ) &(pAddr->m_sockaddr); + memcpy( &(pSystemInetAddr->sin_addr) , pByteSeq->elements , 4 ); + res = osl_Socket_Ok; + } + return res; +} + +/*****************************************************************************/ +/* osl_getAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence **ppByteSeq ) +{ + oslSocketResult res = osl_Socket_Error; + + OSL_ASSERT( pAddr ); + OSL_ASSERT( ppByteSeq ); + + if( pAddr && ppByteSeq ) + { + struct sockaddr_in * pSystemInetAddr = (struct sockaddr_in * ) &(pAddr->m_sockaddr); + rtl_byte_sequence_constructFromArray( ppByteSeq , (sal_Int8 *) &(pSystemInetAddr->sin_addr),4); + res = osl_Socket_Ok; + } + return res; +} + + +/*****************************************************************************/ +/* _osl_getFullQualifiedDomainName */ +/*****************************************************************************/ + +/** try to figure out a full-qualified hostname, by adding the current domain + as given by the domainname program to the given hostname. + This function MUST NOT call gethostbyname since pHostName allready points + to data returned by gethostname and would be garbled: use gethostname_r + instead! + */ + +/* wrap around different interfaces to reentrant gethostbyname */ +static struct hostent* _osl_gethostbyname_r ( + const char *name, struct hostent *result, + char *buffer, int buflen, int *h_errnop) +{ +#if defined(LINUX) || (defined(FREEBSD) && (__FreeBSD_version >= 601103)) + struct hostent *__result; /* will be the same as result */ + int __error; + __error = gethostbyname_r (name, result, buffer, buflen, + &__result, h_errnop); + return __error ? NULL : __result ; +#else + return gethostbyname_r( name, result, buffer, buflen, h_errnop); +#endif +} + +static sal_Bool _osl_getDomainName (sal_Char *buffer, sal_Int32 bufsiz) +{ + sal_Bool result; + int p[2]; + + result = sal_False; + if (pipe (p) == 0) + { + pid_t pid; + int nStatus; + + pid = fork(); + if (pid == 0) + { + char *argv[] = + { + "/bin/domainname", + NULL + }; + + close (p[0]); + dup2 (p[1], 1); + close (p[1]); + + execv ("/bin/domainname", argv); + // arriving here means exec failed + _exit(-1); + } + else if (pid > 0) + { + sal_Int32 k = 0, n = bufsiz; + + close (p[1]); + if ((k = read (p[0], buffer, n - 1)) > 0) + { + buffer[k] = 0; + if (buffer[k - 1] == '\n') + buffer[k - 1] = 0; + result = sal_True; + } + close (p[0]); + waitpid (pid, &nStatus, 0); + } + else + { + close (p[0]); + close (p[1]); + } + } + return (result); +} + +static sal_Char* _osl_getFullQualifiedDomainName (const sal_Char *pHostName) +{ +# define DOMAINNAME_LENGTH 512 + sal_uInt32 nLengthOfHostName; + static sal_uInt32 nLengthOfDomainName = 0; + static sal_Char *pDomainName = NULL; + + sal_Char *pFullQualifiedName; +#if 0 /* OBSOLETE */ + FILE *pPipeToDomainnameExe; +#endif /* OBSOLETE */ + + /* get a '\0' terminated domainname */ + + /* read default domainname default from environment */ + if (nLengthOfDomainName == 0) + { + sal_Char *pEnvDomain; + + pEnvDomain = getenv ("STAR_OVERRIDE_DOMAINNAME"); + if (pEnvDomain) + { + pDomainName = strdup (pEnvDomain); + nLengthOfDomainName = strlen (pDomainName); + } + } + +#if 1 /* NEW */ + if (nLengthOfDomainName == 0) + { + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + + pDomainNameBuffer[0] = '\0'; + + if (_osl_getDomainName (pDomainNameBuffer, DOMAINNAME_LENGTH)) + { + pDomainName = strdup (pDomainNameBuffer); + nLengthOfDomainName = strlen (pDomainName); + } + } + +#endif /* NEW */ +#if 0 /* OBSOLETE */ +#ifdef SCO + + /* call 'domainname > /usr/tmp/some-tmp-file', since + popen read pclose do block or core-dump, + (even the pipe-stuff that comes with pthreads) */ + if (nLengthOfDomainName == 0) + { + sal_Char tmp_name[ L_tmpnam ]; + FILE *tmp_file; + sal_Char domain_call [ L_tmpnam + 16 ] = "domainname > "; + + tmp_name[0] = '\0'; + + tmpnam ( tmp_name ); + strcat ( domain_call, tmp_name ); + if ( (system ( domain_call ) == 0) + && ((tmp_file = fopen( tmp_name, "r" )) != NULL ) ) + { + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + + pDomainNameBuffer[0] = '\0'; + + if ( fgets ( pDomainNameBuffer, DOMAINNAME_LENGTH, tmp_file ) ) + { + pDomainName = strdup( pDomainNameBuffer ); + nLengthOfDomainName = strlen( pDomainName ); + if ( ( nLengthOfDomainName > 0 ) + && ( pDomainName[ nLengthOfDomainName - 1] == '\n' ) ) + pDomainName[ --nLengthOfDomainName ] = '\0'; + } + fclose ( tmp_file ); + } + unlink( tmp_name ); + } + +#else /* !SCO */ + + /* read the domainname from pipe to the program domainname */ + if ( (nLengthOfDomainName == 0) + && (pPipeToDomainnameExe = popen( "domainname", "r")) ) + { + sal_Char c; + sal_Char pDomainNameBuffer[ DOMAINNAME_LENGTH ]; + sal_Char *pDomainNamePointer; + + pDomainNameBuffer[0] = '\0'; + + pDomainNamePointer = pDomainNameBuffer; + while ( ((c = getc( pPipeToDomainnameExe )) != EOF) + && (nLengthOfDomainName < (DOMAINNAME_LENGTH - 1)) ) + { + if (! isspace(c)) + { + nLengthOfDomainName++ ; + *pDomainNamePointer++ = (sal_Char)c; + } + } + *pDomainNamePointer = '\0'; + pDomainName = strdup( pDomainNameBuffer ); + + pclose( pPipeToDomainnameExe ); + } + +#endif /* !SCO */ +#endif /* OBSOLETE */ + + /* compose hostname and domainname */ + nLengthOfHostName = strlen( pHostName ); + pFullQualifiedName = (sal_Char*) malloc( (nLengthOfHostName + 1 + + nLengthOfDomainName + 1) * sizeof(sal_Char) ); + memcpy( pFullQualifiedName, pHostName, + (nLengthOfHostName + 1) * sizeof(sal_Char) ); + + if ( nLengthOfDomainName > 0 ) + { + /* fqdn = hostname + '.' + domainname + '\0' */ + pFullQualifiedName[ nLengthOfHostName ] = '.'; + memcpy( pFullQualifiedName + nLengthOfHostName + 1, pDomainName, + nLengthOfDomainName + 1 ); + } + + /* check whether full-qualified name and hostname point to the same host + * should almost always be true */ + if ( nLengthOfDomainName > 0 ) + { + struct hostent *pQualifiedHostByName; + struct hostent *pHostByName; + sal_Bool bHostsAreEqual; + + /* buffer for calls to reentrant version of gethostbyname */ + struct hostent aHostByName, aQualifiedHostByName; + sal_Char pHostBuffer[ MAX_HOSTBUFFER_SIZE ]; + sal_Char pQualifiedHostBuffer[ MAX_HOSTBUFFER_SIZE ]; + int nErrorNo; + + pHostBuffer[0] = '\0'; + pQualifiedHostBuffer[0] = '\0'; + + /* get list of addresses */ + pQualifiedHostByName = _osl_gethostbyname_r ( + pFullQualifiedName, + &aQualifiedHostByName, pQualifiedHostBuffer, + sizeof(pQualifiedHostBuffer), &nErrorNo ); + pHostByName = _osl_gethostbyname_r ( + pHostName, + &aHostByName, pHostBuffer, + sizeof(pHostBuffer), &nErrorNo ); + + /* compare addresses */ + bHostsAreEqual = sal_False; + if ( pQualifiedHostByName && pHostByName ) + { + sal_Char **p, **q; + struct in_addr in; + + /* lists are expected to be (very) short */ + for ( p = pQualifiedHostByName->h_addr_list; *p != NULL; p++ ) + { + for ( q = pHostByName->h_addr_list; *q != NULL; q++ ) + { + /* in.s_addr may be in_addr_t or uint32_t or heaven knows */ + if ( memcmp( *p, *q, sizeof(in.s_addr) ) == 0 ) + { + bHostsAreEqual = sal_True; + break; + } + } + if ( bHostsAreEqual ) + break; + } + } + + /* very strange case, but have to believe it: reduce the + * full qualified name to the unqualified host name */ + if ( !bHostsAreEqual ) + { + OSL_TRACE("_osl_getFullQualifiedDomainName: " + "suspect FQDN: %s\n", pFullQualifiedName); + + pFullQualifiedName[ nLengthOfHostName ] = '\0'; + pFullQualifiedName = (sal_Char*)realloc ( pFullQualifiedName, + (nLengthOfHostName + 1) * sizeof( sal_Char )); + } + } + + /* always return a hostname looked up as carefully as possible + * this string must be freed by the caller */ + return pFullQualifiedName; +} + +/*****************************************************************************/ +/* _osl_isFullQualifiedDomainName */ +/*****************************************************************************/ +static sal_Bool _osl_isFullQualifiedDomainName (const sal_Char *pHostName) +{ + /* a FQDN (aka 'hostname.domain.top_level_domain' ) + * is a name which contains a dot '.' in it ( would + * match as well for 'hostname.' but is good enough + * for now )*/ + return (sal_Bool)( strchr( pHostName, (int)'.' ) != NULL ); +} + +/*****************************************************************************/ +/* oslHostAddr */ +/*****************************************************************************/ +struct oslHostAddrImpl +{ + sal_Char *pHostName; + oslSocketAddr pSockAddr; +}; + +static oslHostAddr _osl_hostentToHostAddr (const struct hostent *he) +{ + oslHostAddr pAddr= NULL; + oslSocketAddr pSockAddr = 0; + + sal_Char *cn; + + if ((he == NULL) || (he->h_name == NULL) || (he->h_addr_list[0] == NULL)) + return ((oslHostAddr)NULL); + + if (_osl_isFullQualifiedDomainName(he->h_name)) + { + cn= (sal_Char *)malloc(strlen (he->h_name) + 1); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + + strcpy(cn, he->h_name); + } + else + { + cn =_osl_getFullQualifiedDomainName (he->h_name); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + } + + pSockAddr = __osl_createSocketAddr(); + OSL_ASSERT(pSockAddr); + if (pSockAddr == NULL) + { + free(cn); + return ((oslHostAddr)NULL); + } + + pSockAddr->m_sockaddr.sa_family= he->h_addrtype; + if (pSockAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + struct sockaddr_in *sin= (struct sockaddr_in *)&(pSockAddr->m_sockaddr); + memcpy ( + &(sin->sin_addr.s_addr), + he->h_addr_list[0], + he->h_length); + } + else + { + /* unknown address family */ + /* future extensions for new families might be implemented here */ + + OSL_TRACE("_osl_hostentToHostAddr: unknown address family.\n"); + OSL_ASSERT(sal_False); + + __osl_destroySocketAddr( pSockAddr ); + free (cn); + return ((oslHostAddr)NULL); + } + + pAddr= (oslHostAddr) malloc(sizeof(struct oslHostAddrImpl)); + OSL_ASSERT(pAddr); + if (pAddr == NULL) + { + __osl_destroySocketAddr( pSockAddr ); + free (cn); + return ((oslHostAddr)NULL); + } + + pAddr->pHostName= cn; + pAddr->pSockAddr= pSockAddr; + + return pAddr; +} + +/*****************************************************************************/ +/* osl_createHostAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddr ( + rtl_uString *ustrHostname, + const oslSocketAddr Addr) +{ + oslHostAddr HostAddr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName = rtl_string_getStr(strHostname); + } + + HostAddr = osl_psz_createHostAddr(pszHostName,Addr); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + + return HostAddr; +} + +oslHostAddr SAL_CALL osl_psz_createHostAddr ( + const sal_Char *pszHostname, + const oslSocketAddr pAddr) +{ + oslHostAddr pHostAddr; + sal_Char *cn; + + OSL_ASSERT(pszHostname && pAddr); + if ((pszHostname == NULL) || (pAddr == NULL)) + return ((oslHostAddr)NULL); + + cn = (sal_Char *)malloc(strlen (pszHostname) + 1); + OSL_ASSERT(cn); + if (cn == NULL) + return ((oslHostAddr)NULL); + + strcpy (cn, pszHostname); + + pHostAddr= (oslHostAddr) malloc(sizeof(struct oslHostAddrImpl)); + OSL_ASSERT(pHostAddr); + if (pAddr == NULL) + { + free (cn); + return ((oslHostAddr)NULL); + } + + pHostAddr->pHostName= cn; + pHostAddr->pSockAddr= osl_copySocketAddr( pAddr ); + + return pHostAddr; +} + +/*****************************************************************************/ +/* osl_createHostAddrByName */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddrByName(rtl_uString *ustrHostname) +{ + oslHostAddr HostAddr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName=rtl_string_getStr(strHostname); + } + + HostAddr = osl_psz_createHostAddrByName(pszHostName); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + return HostAddr; +} + +oslHostAddr SAL_CALL osl_psz_createHostAddrByName (const sal_Char *pszHostname) +{ + struct hostent *he; + oslHostAddr addr; + + static oslMutex mutex = NULL; + + if (mutex == NULL) + mutex = osl_createMutex(); + + osl_acquireMutex(mutex); + + he = gethostbyname((sal_Char *)pszHostname); + addr = _osl_hostentToHostAddr (he); + + osl_releaseMutex(mutex); + + return addr; +} + +/*****************************************************************************/ +/* osl_createHostAddrByAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_createHostAddrByAddr (const oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr == NULL) + return ((oslHostAddr)NULL); + + if (pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + const struct sockaddr_in *sin= (const struct sockaddr_in *)&(pAddr->m_sockaddr); + struct hostent *he; + + if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) + return ((oslHostAddr)NULL); + + he= gethostbyaddr((sal_Char *)&(sin->sin_addr), + sizeof (sin->sin_addr), + sin->sin_family); + return _osl_hostentToHostAddr (he); + } + + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_copyHostAddr */ +/*****************************************************************************/ +oslHostAddr SAL_CALL osl_copyHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return osl_psz_createHostAddr (pAddr->pHostName, pAddr->pSockAddr); + else + return ((oslHostAddr)NULL); +} + +/*****************************************************************************/ +/* osl_getHostnameOfHostAddr */ +/*****************************************************************************/ +void SAL_CALL osl_getHostnameOfHostAddr ( + const oslHostAddr Addr, + rtl_uString **ustrHostname) +{ + const sal_Char* pHostname=0; + + pHostname = osl_psz_getHostnameOfHostAddr(Addr); + + rtl_uString_newFromAscii (ustrHostname, pHostname); + + return; +} + +const sal_Char* SAL_CALL osl_psz_getHostnameOfHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return pAddr->pHostName; + else + return NULL; +} + +/*****************************************************************************/ +/* osl_getSocketAddrOfHostAddr */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getSocketAddrOfHostAddr (const oslHostAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return ((oslSocketAddr)(pAddr->pSockAddr)); + else + return NULL; +} + +/*****************************************************************************/ +/* osl_destroyHostAddr */ +/*****************************************************************************/ +void SAL_CALL osl_destroyHostAddr (oslHostAddr pAddr) +{ + if (pAddr) + { + if (pAddr->pHostName) + free (pAddr->pHostName); + if (pAddr->pSockAddr) + osl_destroySocketAddr (pAddr->pSockAddr); + free (pAddr); + } +} + +/*****************************************************************************/ +/* osl_getLocalHostname */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getLocalHostname(rtl_uString **ustrLocalHostname) +{ + oslSocketResult Result; + sal_Char pszHostname[1024]; + + pszHostname[0] = '\0'; + + Result = osl_psz_getLocalHostname(pszHostname,sizeof(pszHostname)); + + rtl_uString_newFromAscii(ustrLocalHostname,pszHostname); + + return Result; +} + +oslSocketResult SAL_CALL osl_psz_getLocalHostname ( + sal_Char *pBuffer, sal_uInt32 nBufLen) +{ + static sal_Char LocalHostname[256] = ""; + + if (strlen(LocalHostname) == 0) + { + const sal_Char *pStr; + +#ifdef SYSV + struct utsname uts; + + if (uname(&uts) < 0) + return osl_Socket_Error; + + if ((strlen(uts.nodename) + 1) > nBufLen) + return osl_Socket_Error; + + strncpy(LocalHostname, uts.nodename, sizeof( LocalHostname )); +#else /* BSD compatible */ + + if (gethostname(LocalHostname, sizeof(LocalHostname)-1) != 0) + return osl_Socket_Error; + LocalHostname[sizeof(LocalHostname)-1] = 0; +#endif /* SYSV */ + + /* check if we have an FQDN */ + if (strchr(LocalHostname, '.') == NULL) + { + oslHostAddr Addr; + + /* no, determine it via dns */ + Addr = osl_psz_createHostAddrByName(LocalHostname); + + if ((pStr = osl_psz_getHostnameOfHostAddr(Addr)) != NULL) + { +#if 0 /* OBSOLETE */ + sal_Char* pChr; +#endif /* OBSOLETE */ + strcpy(LocalHostname, pStr); + +#if 0 /* OBSOLETE */ + /* already done by _osl_getFullQualifiedDomainName() with + much better heuristics, so this may be contraproductive */ + + /* no FQDN, last try append domain name */ + if ((pChr = strchr(LocalHostname, '.')) == NULL) + { + FILE *fp; + + pChr = &LocalHostname[strlen(LocalHostname)]; + + if ( (fp = popen("domainname", "r")) != 0 ) + { + int c; + + *pChr++ = '.'; + + while ((c = getc(fp)) != EOF) + { + if (! isspace(c)) + *pChr++ = (sal_Char)c; + } + + *pChr = '\0'; + + fclose(fp); + } + else + LocalHostname[0] = '\0'; + } +#endif /* OBSOLETE */ + + } + osl_destroyHostAddr(Addr); + } + } + + if (strlen(LocalHostname) > 0) + { + strncpy(pBuffer, LocalHostname, nBufLen); + pBuffer[nBufLen - 1] = '\0'; + + return osl_Socket_Ok; + } + + return osl_Socket_Error; +} + +/*****************************************************************************/ +/* osl_resolveHostname */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_resolveHostname(rtl_uString *ustrHostname) +{ + oslSocketAddr Addr; + rtl_String* strHostname=0; + sal_Char* pszHostName=0; + + if ( ustrHostname != 0 ) + { + rtl_uString2String( &strHostname, + rtl_uString_getStr(ustrHostname), + rtl_uString_getLength(ustrHostname), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszHostName = rtl_string_getStr(strHostname); + } + + + Addr = osl_psz_resolveHostname(pszHostName); + + if ( strHostname != 0 ) + { + rtl_string_release(strHostname); + } + + + return Addr; +} + + +oslSocketAddr SAL_CALL osl_psz_resolveHostname(const sal_Char* pszHostname) +{ + struct oslHostAddrImpl *pAddr = (oslHostAddr)osl_psz_createHostAddrByName(pszHostname); + + if (pAddr) + { + oslSocketAddr SockAddr = osl_copySocketAddr(pAddr->pSockAddr); + + osl_destroyHostAddr(pAddr); + + return (SockAddr); + } + + return ((oslSocketAddr)NULL); +} + +/*****************************************************************************/ +/* osl_getServicePort */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getServicePort(rtl_uString *ustrServicename, rtl_uString *ustrProtocol) +{ + sal_Int32 nPort; + rtl_String* strServicename=0; + rtl_String* strProtocol=0; + sal_Char* pszServiceName=0; + sal_Char* pszProtocol=0; + + if ( ustrServicename != 0 ) + { + rtl_uString2String( &strServicename, + rtl_uString_getStr(ustrServicename), + rtl_uString_getLength(ustrServicename), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszServiceName = rtl_string_getStr(strServicename); + } + + if ( ustrProtocol != 0 ) + { + rtl_uString2String( &strProtocol, + rtl_uString_getStr(ustrProtocol), + rtl_uString_getLength(ustrProtocol), + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS ); + pszProtocol = rtl_string_getStr(strProtocol); + } + + nPort = osl_psz_getServicePort(pszServiceName,pszProtocol); + + if ( strServicename != 0 ) + { + rtl_string_release(strServicename); + } + + if ( strProtocol != 0 ) + { + rtl_string_release(strProtocol); + } + + + return nPort; +} + + +sal_Int32 SAL_CALL osl_psz_getServicePort(const sal_Char* pszServicename, + const sal_Char* pszProtocol) +{ + struct servent* ps; + + ps= getservbyname(pszServicename, pszProtocol); + + if (ps != 0) + return ntohs(ps->s_port); + + return OSL_INVALID_PORT; +} + +/*****************************************************************************/ +/* osl_destroySocketAddr */ +/*****************************************************************************/ +void SAL_CALL osl_destroySocketAddr(oslSocketAddr pAddr) +{ + __osl_destroySocketAddr( pAddr ); +} + +/*****************************************************************************/ +/* osl_getFamilyOfSocketAddr */ +/*****************************************************************************/ +oslAddrFamily SAL_CALL osl_getFamilyOfSocketAddr(oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + + if (pAddr) + return FAMILY_FROM_NATIVE(pAddr->m_sockaddr.sa_family); + else + return osl_Socket_FamilyInvalid; +} + +/*****************************************************************************/ +/* osl_getInetPortOfSocketAddr */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getInetPortOfSocketAddr(oslSocketAddr pAddr) +{ + OSL_ASSERT(pAddr); + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + + if ( pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + return ntohs(pSystemInetAddr->sin_port); + } + return OSL_INVALID_PORT; +} + +/*****************************************************************************/ +/* osl_setInetPortOfSocketAddr */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setInetPortOfSocketAddr(oslSocketAddr pAddr, sal_Int32 Port) +{ + OSL_ASSERT(pAddr); + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr= (struct sockaddr_in*)&(pAddr->m_sockaddr); + if ( pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + pSystemInetAddr->sin_port= htons((short)Port); + return sal_True; + } + } + + /* this is not a inet-addr => can't set port */ + return sal_False; +} + +/*****************************************************************************/ +/* osl_getHostnameOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getHostnameOfSocketAddr(oslSocketAddr Addr, rtl_uString **ustrHostname) +{ + oslSocketResult Result; + sal_Char pszHostname[1024]; + + pszHostname[0] = '\0'; + + Result = osl_psz_getHostnameOfSocketAddr(Addr,pszHostname,sizeof(pszHostname)); + + rtl_uString_newFromAscii(ustrHostname,pszHostname); + + return Result; +} + + +oslSocketResult SAL_CALL osl_psz_getHostnameOfSocketAddr(oslSocketAddr pAddr, + sal_Char *pBuffer, sal_uInt32 BufferSize) +{ + oslHostAddr pHostAddr= (oslHostAddr )osl_createHostAddrByAddr(pAddr); + + if (pHostAddr) + { + strncpy(pBuffer, pHostAddr->pHostName, BufferSize); + + pBuffer[BufferSize - 1] = '\0'; + + osl_destroyHostAddr(pHostAddr); + + return osl_Socket_Ok; + } + + return osl_Socket_Error; +} + +/*****************************************************************************/ +/* osl_getDottedInetAddrOfSocketAddr */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getDottedInetAddrOfSocketAddr(oslSocketAddr Addr, rtl_uString **ustrDottedInetAddr) +{ + oslSocketResult Result; + sal_Char pszDottedInetAddr[1024]; + + pszDottedInetAddr[0] = '\0'; + + Result = osl_psz_getDottedInetAddrOfSocketAddr(Addr,pszDottedInetAddr,sizeof(pszDottedInetAddr)); + + rtl_uString_newFromAscii(ustrDottedInetAddr,pszDottedInetAddr); + + return Result; + +} + +oslSocketResult SAL_CALL osl_psz_getDottedInetAddrOfSocketAddr(oslSocketAddr pAddr, + sal_Char *pBuffer, sal_uInt32 BufferSize) +{ + OSL_ASSERT(pAddr); + + if( pAddr ) + { + struct sockaddr_in* pSystemInetAddr = ( struct sockaddr_in * ) &(pAddr->m_sockaddr); + + if (pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) + { + strncpy(pBuffer, inet_ntoa(pSystemInetAddr->sin_addr), BufferSize); + pBuffer[BufferSize - 1] = '\0'; + + return osl_Socket_Ok; + } + } + + return osl_Socket_Error; +} + +#if 0 /* OBSOLETE */ +/*****************************************************************************/ +/* osl_getIpxNetNumber */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getIpxNetNumber(oslSocketAddr Addr, + oslSocketIpxNetNumber NetNumber) + +{ + struct sockaddr_ipx* pAddr; + + pAddr= (struct sockaddr_ipx*)Addr; + + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + { + memcpy(NetNumber, pAddr->sa_netnum, sizeof(NetNumber)); + + return osl_Socket_Ok; + } + else + return osl_Socket_Error; +} + + +/*****************************************************************************/ +/* osl_getIpxNodeNumber */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_getIpxNodeNumber(oslSocketAddr Addr, + oslSocketIpxNodeNumber NodeNumber) + +{ + struct sockaddr_ipx* pAddr; + + pAddr= (struct sockaddr_ipx*)Addr; + + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + { + memcpy(NodeNumber, pAddr->sa_nodenum, sizeof(NodeNumber)); + + return osl_Socket_Ok; + } + else + return osl_Socket_Error; +} + + +/*****************************************************************************/ +/* osl_getIpxSocketNumber */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getIpxSocketNumber(oslSocketAddr Addr) +{ + struct sockaddr_ipx* pAddr= (struct sockaddr_ipx*)Addr; + OSL_ASSERT(pAddr); + + if (pAddr && (pAddr->sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyIpx))) + return pAddr->sa_socket; + else + return OSL_INVALID_IPX_SOCKET_NO; +} + +#endif /* OBSOLETE */ + +/*****************************************************************************/ +/* osl_createSocket */ +/*****************************************************************************/ +oslSocket SAL_CALL osl_createSocket(oslAddrFamily Family, + oslSocketType Type, + oslProtocol Protocol) +{ + int Flags; + oslSocket pSocket; + + /* alloc memory */ + pSocket= __osl_createSocketImpl(OSL_INVALID_SOCKET); + + /* create socket */ + pSocket->m_Socket= socket(FAMILY_TO_NATIVE(Family), + TYPE_TO_NATIVE(Type), + PROTOCOL_TO_NATIVE(Protocol)); + + /* creation failed => free memory */ + if(pSocket->m_Socket == OSL_INVALID_SOCKET) + { + OSL_TRACE("osl_createSocket failed. Errno: %d; %s\n", + errno, + strerror(errno)); + + __osl_destroySocketImpl((pSocket)); + pSocket= 0; + } + else + { + /* set close-on-exec flag */ + if ((Flags = fcntl(pSocket->m_Socket, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + if (fcntl(pSocket->m_Socket, F_SETFD, Flags) == -1) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_createSocket failed changing socket flags. Errno: %d; %s\n", + errno, + strerror(errno)); + } + } + else + { + pSocket->m_nLastError=errno; + } + + + pSocket->m_CloseCallback = NULL; + pSocket->m_CallbackArg = NULL; + } + + return pSocket; +} + +void SAL_CALL osl_acquireSocket(oslSocket pSocket) +{ + osl_incrementInterlockedCount( &(pSocket->m_nRefCount ) ); +} + +void SAL_CALL osl_releaseSocket( oslSocket pSocket ) +{ + if( pSocket && 0 == osl_decrementInterlockedCount( &(pSocket->m_nRefCount) ) ) + { +#if defined(LINUX) + if ( pSocket->m_bIsAccepting == sal_True ) + { + OSL_ENSURE(0, "osl_destroySocket : attempt to destroy socket while accepting\n"); + return; + } +#endif /* LINUX */ + osl_closeSocket( pSocket ); + __osl_destroySocketImpl( pSocket ); + } +} + + + +/*****************************************************************************/ +/* osl_closeSocket */ +/*****************************************************************************/ +void SAL_CALL osl_closeSocket(oslSocket pSocket) +{ + int nRet; + int nFD; + + /* socket already invalid */ + if(pSocket==0) + return; + + pSocket->m_nLastError=0; + nFD = pSocket->m_Socket; + + if (nFD == OSL_INVALID_SOCKET) + return; + + pSocket->m_Socket = OSL_INVALID_SOCKET; + +#if defined(LINUX) + pSocket->m_bIsInShutdown = sal_True; + + if ( pSocket->m_bIsAccepting == sal_True ) + { + int nConnFD; + union { + struct sockaddr aSockAddr; + struct sockaddr_in aSockAddrIn; + } s; + socklen_t nSockLen = sizeof(s.aSockAddr); + + nRet = getsockname(nFD, &s.aSockAddr, &nSockLen); +#if OSL_DEBUG_LEVEL > 1 + if ( nRet < 0 ) + { + perror("getsockname"); + } +#endif /* OSL_DEBUG_LEVEL */ + + if ( s.aSockAddr.sa_family == AF_INET ) + { + if ( s.aSockAddrIn.sin_addr.s_addr == htonl(INADDR_ANY) ) + { + s.aSockAddrIn.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + + nConnFD = socket(AF_INET, SOCK_STREAM, 0); +#if OSL_DEBUG_LEVEL > 1 + if ( nConnFD < 0 ) + { + perror("socket"); + } +#endif /* OSL_DEBUG_LEVEL */ + + nRet = connect(nConnFD, &s.aSockAddr, sizeof(s.aSockAddr)); +#if OSL_DEBUG_LEVEL > 1 + if ( nRet < 0 ) + { + perror("connect"); + } +#endif /* OSL_DEBUG_LEVEL */ + close(nConnFD); + } + pSocket->m_bIsAccepting = sal_False; + } +#endif /* LINUX */ + + /* registrierten Callback ausfuehren */ + if (pSocket->m_CloseCallback != NULL) + { + pSocket->m_CloseCallback(pSocket->m_CallbackArg); + } + + nRet=close(nFD); + if ( nRet != 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("closeSocket close error '%s'\n",strerror(errno)); + } + + pSocket->m_Socket = OSL_INVALID_SOCKET; +} + +/*****************************************************************************/ +/* osl_getLocalAddrOfSocket */ +/* Note that I rely on the fact that oslSocketAddr and struct sockaddr */ +/* are the same! I don't like it very much but see no other easy way to conceal */ +/* the struct sockaddr from the eyes of the user. */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getLocalAddrOfSocket(oslSocket pSocket) +{ + socklen_t AddrLen; + struct sockaddr Addr; + oslSocketAddr pAddr; + + if (pSocket == NULL) /* ENOTSOCK */ + return ((oslSocketAddr)NULL); + + AddrLen= sizeof(struct sockaddr); + + if (getsockname(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR) + return ((oslSocketAddr)NULL); + + pAddr = __osl_createSocketAddrFromSystem( &Addr ); + return pAddr; +} + +/*****************************************************************************/ +/* osl_getPeerAddrOfSocket */ +/*****************************************************************************/ +oslSocketAddr SAL_CALL osl_getPeerAddrOfSocket(oslSocket pSocket) +{ + socklen_t AddrLen; + struct sockaddr Addr; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return 0; + } + + pSocket->m_nLastError=0; + AddrLen= sizeof(struct sockaddr); + + if(getpeername(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return 0; + } + return __osl_createSocketAddrFromSystem( &Addr ); +} + +/*****************************************************************************/ +/* osl_bindAddrToSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_bindAddrToSocket(oslSocket pSocket, + oslSocketAddr pAddr) +{ + int nRet; + + OSL_ASSERT(pSocket && pAddr ); + if ( pSocket == 0 || pAddr == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = bind(pSocket->m_Socket, &(pAddr->m_sockaddr), sizeof(struct sockaddr)); + + if ( nRet == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + + +/*****************************************************************************/ +/* osl_listenOnSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_listenOnSocket(oslSocket pSocket, + sal_Int32 MaxPendingConnections) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = listen(pSocket->m_Socket, + MaxPendingConnections == -1 ? + SOMAXCONN : + MaxPendingConnections); + if ( nRet == OSL_SOCKET_ERROR) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + + +/*****************************************************************************/ +/* osl_connectSocketTo */ +/*****************************************************************************/ +oslSocketResult SAL_CALL osl_connectSocketTo(oslSocket pSocket, + oslSocketAddr pAddr, + const TimeValue* pTimeout) +{ + fd_set WriteSet; + fd_set ExcptSet; + int ReadyHandles; + struct timeval tv; + oslSocketResult Result= osl_Socket_Ok; + + OSL_PRECOND(pSocket, "osl_connectSocketTo(): need a valid socket!\n"); + + if ( pSocket == 0 ) + { + return osl_Socket_Error; + } + + pSocket->m_nLastError=0; + + if (osl_isNonBlockingMode(pSocket)) + { + if (connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) != OSL_SOCKET_ERROR) + return osl_Socket_Ok; + else + if (errno == EWOULDBLOCK || errno == EINPROGRESS) + { + pSocket->m_nLastError=EINPROGRESS; + return osl_Socket_InProgress; + } + + + pSocket->m_nLastError=errno; + OSL_TRACE("can't connect : '%s'",strerror(errno)); + return osl_Socket_Error; + } + + /* set socket temporarily to non-blocking */ + OSL_VERIFY(osl_enableNonBlockingMode(pSocket, sal_True)); + + /* initiate connect */ + if(connect(pSocket->m_Socket, + &(pAddr->m_sockaddr), + sizeof(struct sockaddr)) != OSL_SOCKET_ERROR) + { + /* immediate connection */ + osl_enableNonBlockingMode(pSocket, sal_False); + + return osl_Socket_Ok; + } + else + { + /* really an error or just delayed? */ + if (errno != EINPROGRESS) + { + pSocket->m_nLastError=errno; + OSL_TRACE( + "osl_connectSocketTo(): connect failed: errno: %d (%s)\n", + errno, strerror(errno)); + + osl_enableNonBlockingMode(pSocket, sal_False); + return osl_Socket_Error; + } + } + + + /* prepare select set for socket */ + FD_ZERO(&WriteSet); + FD_ZERO(&ExcptSet); + FD_SET(pSocket->m_Socket, &WriteSet); + FD_SET(pSocket->m_Socket, &ExcptSet); + + /* prepare timeout */ + if (pTimeout) + { + /* divide milliseconds into seconds and microseconds */ + tv.tv_sec= pTimeout->Seconds; + tv.tv_usec= pTimeout->Nanosec / 1000L; + } + + /* select */ + ReadyHandles= select(pSocket->m_Socket+1, + 0, + PTR_FD_SET(WriteSet), + PTR_FD_SET(ExcptSet), + (pTimeout) ? &tv : 0); + + if (ReadyHandles > 0) /* connected */ + { + if ( FD_ISSET(pSocket->m_Socket, &WriteSet ) ) + { + int nErrorCode = 0; + socklen_t nErrorSize = sizeof( nErrorCode ); + + int nSockOpt; + + nSockOpt = getsockopt ( pSocket->m_Socket, SOL_SOCKET, SO_ERROR, + &nErrorCode, &nErrorSize ); + if ( (nSockOpt == 0) && (nErrorCode == 0)) + Result = osl_Socket_Ok; + else + Result = osl_Socket_Error; + } + else + { + Result= osl_Socket_Error; + } + } + else if (ReadyHandles < 0) /* error */ + { + if (errno == EBADF) /* most probably interrupted by close() */ + { + /* do not access pSockImpl because it is about to be or */ + /* already destroyed */ + return osl_Socket_Interrupted; + } + else + { + pSocket->m_nLastError=errno; + Result= osl_Socket_Error; + } + } + else /* timeout */ + { + pSocket->m_nLastError=errno; + Result= osl_Socket_TimedOut; + } + + osl_enableNonBlockingMode(pSocket, sal_False); + + return Result; +} + + +/*****************************************************************************/ +/* osl_acceptConnectionOnSocket */ +/*****************************************************************************/ +oslSocket SAL_CALL osl_acceptConnectionOnSocket(oslSocket pSocket, + oslSocketAddr* ppAddr) +{ + struct sockaddr Addr; + int Connection, Flags; + oslSocket pConnectionSockImpl; + + socklen_t AddrLen = sizeof(struct sockaddr); + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return 0; + } + + pSocket->m_nLastError=0; +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_True; +#endif /* LINUX */ + + if( ppAddr && *ppAddr ) + { + osl_destroySocketAddr( *ppAddr ); + *ppAddr = 0; + } + + /* prevent Linux EINTR behaviour */ + do + { + Connection = accept(pSocket->m_Socket, &Addr, &AddrLen); + } while (Connection == -1 && errno == EINTR); + + + /* accept failed? */ + if( Connection == OSL_SOCKET_ERROR ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_acceptConnectionOnSocket : accept error '%s'\n",strerror(errno)); + +#if defined(LINUX) + pSocket->m_bIsAccepting = sal_False; +#endif /* LINUX */ + return 0; + } + + OSL_ASSERT(AddrLen == sizeof(struct sockaddr)); + + +#if defined(LINUX) + if ( pSocket->m_bIsInShutdown == sal_True ) + { + close(Connection); + OSL_TRACE("osl_acceptConnectionOnSocket : close while accept\n"); + return 0; + } +#endif /* LINUX */ + + + if(ppAddr) + { + *ppAddr= __osl_createSocketAddrFromSystem(&Addr); + } + + /* alloc memory */ + pConnectionSockImpl= __osl_createSocketImpl(OSL_INVALID_SOCKET); + + /* set close-on-exec flag */ + if ((Flags = fcntl(Connection, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + if (fcntl(Connection, F_SETFD, Flags) == -1) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_acceptConnectionOnSocket failed changing socket flags. Errno: %d (%s)\n", + errno, + strerror(errno)); + } + + } + + pConnectionSockImpl->m_Socket = Connection; + pConnectionSockImpl->m_nLastError = 0; + pConnectionSockImpl->m_CloseCallback = NULL; + pConnectionSockImpl->m_CallbackArg = NULL; +#if defined(LINUX) + pConnectionSockImpl->m_bIsAccepting = sal_False; + + pSocket->m_bIsAccepting = sal_False; +#endif /* LINUX */ + return pConnectionSockImpl; +} + +/*****************************************************************************/ +/* osl_receiveSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receiveSocket(oslSocket pSocket, + void* pBuffer, + sal_uInt32 BytesToRead, + oslSocketMsgFlag Flag) +{ + int nRead; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_receiveSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + do + { + nRead = recv(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToRead, + MSG_FLAG_TO_NATIVE(Flag)); + } while ( nRead < 0 && errno == EINTR ); + + if ( nRead < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,strerror(errno)); + } + else if ( nRead == 0 ) + { + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,"EOL"); + } + + return nRead; +} + + +/*****************************************************************************/ +/* osl_receiveFromSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_receiveFromSocket(oslSocket pSocket, + oslSocketAddr pSenderAddr, + void* pBuffer, + sal_uInt32 BufferSize, + oslSocketMsgFlag Flag) +{ + int nRead; + struct sockaddr *pSystemSockAddr = 0; + socklen_t AddrLen = 0; + if( pSenderAddr ) + { + AddrLen = sizeof( struct sockaddr ); + pSystemSockAddr = &(pSenderAddr->m_sockaddr); + } + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_receiveFromSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + nRead = recvfrom(pSocket->m_Socket, + (sal_Char*)pBuffer, + BufferSize, + MSG_FLAG_TO_NATIVE(Flag), + pSystemSockAddr, + &AddrLen); + + if ( nRead < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_receiveFromSocket failed : %i '%s'",nRead,strerror(errno)); + } + else if ( nRead == 0 ) + { + OSL_TRACE("osl_receiveSocket failed : %i '%s'",nRead,"EOL"); + } + + return nRead; +} + + +/*****************************************************************************/ +/* osl_sendSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendSocket(oslSocket pSocket, + const void* pBuffer, + sal_uInt32 BytesToSend, + oslSocketMsgFlag Flag) +{ + int nWritten; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_sendSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + do + { + nWritten = send(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, + MSG_FLAG_TO_NATIVE(Flag)); + } while ( nWritten < 0 && errno == EINTR ); + + + if ( nWritten < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_sendSocket failed : %i '%s'",nWritten,strerror(errno)); + } + else if ( nWritten == 0 ) + { + OSL_TRACE("osl_sendSocket failed : %i '%s'",nWritten,"EOL"); + } + + return nWritten; +} + +/*****************************************************************************/ +/* osl_sendToSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_sendToSocket(oslSocket pSocket, + oslSocketAddr ReceiverAddr, + const void* pBuffer, + sal_uInt32 BytesToSend, + oslSocketMsgFlag Flag) +{ + int nWritten; + + struct sockaddr *pSystemSockAddr = 0; + int AddrLen = 0; + if( ReceiverAddr ) + { + pSystemSockAddr = &(ReceiverAddr->m_sockaddr); + AddrLen = sizeof( struct sockaddr ); + } + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + OSL_TRACE("osl_sendToSocket : Invalid socket"); + return -1; + } + + pSocket->m_nLastError=0; + + /* ReceiverAddr might be 0 when used on a connected socket. */ + /* Then sendto should behave like send. */ + + nWritten = sendto(pSocket->m_Socket, + (sal_Char*)pBuffer, + BytesToSend, + MSG_FLAG_TO_NATIVE(Flag), + pSystemSockAddr, + AddrLen); + + if ( nWritten < 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("osl_sendToSocket failed : %i '%s'",nWritten,strerror(errno)); + } + else if ( nWritten == 0 ) + { + OSL_TRACE("osl_sendToSocket failed : %i '%s'",nWritten,"EOL"); + } + + return nWritten; +} + +/*****************************************************************************/ +/* osl_readSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_readSocket ( + oslSocket pSocket, void *pBuffer, sal_Int32 n ) +{ + sal_uInt8 * Ptr = (sal_uInt8 *)pBuffer; + sal_uInt32 BytesRead= 0; + sal_uInt32 BytesToRead= n; + + OSL_ASSERT( pSocket); + + /* loop until all desired bytes were read or an error occured */ + while (BytesToRead > 0) + { + sal_Int32 RetVal; + RetVal= osl_receiveSocket(pSocket, + Ptr, + BytesToRead, + osl_Socket_MsgNormal); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToRead -= RetVal; + BytesRead += RetVal; + Ptr += RetVal; + } + + return BytesRead; +} + +/*****************************************************************************/ +/* osl_writeSocket */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_writeSocket( + oslSocket pSocket, const void *pBuffer, sal_Int32 n ) +{ + /* loop until all desired bytes were send or an error occured */ + sal_uInt32 BytesSend= 0; + sal_uInt32 BytesToSend= n; + sal_uInt8 *Ptr = ( sal_uInt8 * )pBuffer; + + OSL_ASSERT( pSocket ); + + while (BytesToSend > 0) + { + sal_Int32 RetVal; + + RetVal= osl_sendSocket( pSocket,Ptr,BytesToSend,osl_Socket_MsgNormal); + + /* error occured? */ + if(RetVal <= 0) + { + break; + } + + BytesToSend -= RetVal; + BytesSend += RetVal; + Ptr += RetVal; + + } + return BytesSend; +} + +/*****************************************************************************/ +/* __osl_socket_poll */ +/*****************************************************************************/ + +#ifdef HAVE_POLL_H /* poll() */ + +sal_Bool __osl_socket_poll ( + oslSocket pSocket, + const TimeValue* pTimeout, + short nEvent) +{ + struct pollfd fds; + int timeout; + int result; + + OSL_ASSERT(pSocket); + pSocket->m_nLastError = 0; + + fds.fd = pSocket->m_Socket; + fds.events = nEvent; + fds.revents = 0; + + timeout = -1; + if (pTimeout) + { + /* Convert to [ms] */ + timeout = pTimeout->Seconds * 1000; + timeout += pTimeout->Nanosec / (1000 * 1000); + } + + result = poll (&fds, 1, timeout); + if (result < 0) + { + pSocket->m_nLastError = errno; + OSL_TRACE("__osl_socket_poll(): poll error: %d (%s)", + errno, strerror(errno)); + return sal_False; + } + if (result == 0) + { + /* Timeout */ + return sal_False; + } + + return ((fds.revents & nEvent) == nEvent); +} + +#else /* select() */ + +sal_Bool __osl_socket_poll ( + oslSocket pSocket, + const TimeValue* pTimeout, + short nEvent) +{ + fd_set fds; + struct timeval tv; + int result; + + OSL_ASSERT(pSocket); + pSocket->m_nLastError = 0; + + FD_ZERO(&fds); + FD_SET(pSocket->m_Socket, &fds); + + if (pTimeout) + { + /* Convert to 'timeval' */ + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000; + } + + result = select ( + pSocket->m_Socket + 1, + (nEvent == POLLIN ) ? PTR_FD_SET(fds) : NULL, + (nEvent == POLLOUT) ? PTR_FD_SET(fds) : NULL, + (nEvent == POLLPRI) ? PTR_FD_SET(fds) : NULL, + (pTimeout) ? &tv : NULL); + + if (result < 0) + { + pSocket->m_nLastError = errno; + OSL_TRACE("__osl_socket_poll(): select error: %d (%s)", + errno, strerror(errno)); + return sal_False; + } + if (result == 0) + { + /* Timeout */ + return sal_False; + } + + return (FD_ISSET(pSocket->m_Socket, &fds) ? sal_True : sal_False); +} + +#endif /* HAVE_POLL_H */ + +/*****************************************************************************/ +/* osl_isReceiveReady */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isReceiveReady ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLIN); +} + +/*****************************************************************************/ +/* osl_isSendReady */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isSendReady ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLOUT); +} + +/*****************************************************************************/ +/* osl_isExceptionPending */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isExceptionPending ( + oslSocket pSocket, const TimeValue* pTimeout) +{ + OSL_ASSERT(pSocket); + if (pSocket == NULL) + { + /* ENOTSOCK */ + return sal_False; + } + + return __osl_socket_poll (pSocket, pTimeout, POLLPRI); +} + +/*****************************************************************************/ +/* osl_shutdownSocket */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_shutdownSocket(oslSocket pSocket, + oslSocketDirection Direction) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet=shutdown(pSocket->m_Socket, DIRECTION_TO_NATIVE(Direction)); + if (nRet != 0 ) + { + pSocket->m_nLastError=errno; + OSL_TRACE("shutdown error '%s'\n",strerror(errno)); + } + return (nRet==0); +} + + +/*****************************************************************************/ +/* osl_getSocketOption */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_getSocketOption(oslSocket pSocket, + oslSocketOptionLevel Level, + oslSocketOption Option, + void* pBuffer, + sal_uInt32 BufferLen) +{ + socklen_t nOptLen = (socklen_t) BufferLen; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return -1; + } + + pSocket->m_nLastError=0; + + if(getsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(Level), + OPTION_TO_NATIVE(Option), + (sal_Char*)pBuffer, + &nOptLen) == -1) + { + pSocket->m_nLastError=errno; + return -1; + } + + return BufferLen; +} + +/*****************************************************************************/ +/* osl_setSocketOption */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setSocketOption(oslSocket pSocket, + oslSocketOptionLevel Level, + oslSocketOption Option, + void* pBuffer, + sal_uInt32 BufferLen) +{ + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + nRet = setsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(Level), + OPTION_TO_NATIVE(Option), + (sal_Char*)pBuffer, + BufferLen); + + if ( nRet < 0 ) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + +/*****************************************************************************/ +/* osl_enableNonBlockingMode */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_enableNonBlockingMode(oslSocket pSocket, + sal_Bool On) +{ + int flags; + int nRet; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + flags = fcntl(pSocket->m_Socket, F_GETFL, 0); + + if (On) + flags |= O_NONBLOCK; + else + flags &= ~(O_NONBLOCK); + + nRet = fcntl(pSocket->m_Socket, F_SETFL, flags); + + if ( nRet < 0 ) + { + pSocket->m_nLastError=errno; + return sal_False; + } + + return sal_True; +} + +/*****************************************************************************/ +/* osl_isNonBlockingMode */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isNonBlockingMode(oslSocket pSocket) +{ + int flags; + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return sal_False; + } + + pSocket->m_nLastError=0; + + flags = fcntl(pSocket->m_Socket, F_GETFL, 0); + + if (flags == -1 || !(flags & O_NONBLOCK)) + return sal_False; + else + return sal_True; +} + +/*****************************************************************************/ +/* osl_getSocketType */ +/*****************************************************************************/ +oslSocketType SAL_CALL osl_getSocketType(oslSocket pSocket) +{ + int Type=0; + socklen_t TypeSize= sizeof(Type); + + OSL_ASSERT(pSocket); + if ( pSocket == 0 ) + { + return osl_Socket_TypeInvalid; + } + + pSocket->m_nLastError=0; + + if(getsockopt(pSocket->m_Socket, + OPTION_LEVEL_TO_NATIVE(osl_Socket_LevelSocket), + OPTION_TO_NATIVE(osl_Socket_OptionType), + (sal_Char*)&Type, + &TypeSize) == -1) + { + /* error */ + pSocket->m_nLastError=errno; + return osl_Socket_TypeInvalid; + } + + return TYPE_FROM_NATIVE(Type); + +} + +/*****************************************************************************/ +/* osl_getLastSocketErrorDescription */ +/*****************************************************************************/ +void SAL_CALL osl_getLastSocketErrorDescription(oslSocket Socket, rtl_uString **ustrError) +{ + sal_Char pszError[1024]; + + pszError[0] = '\0'; + + osl_psz_getLastSocketErrorDescription(Socket,pszError,sizeof(pszError)); + + rtl_uString_newFromAscii(ustrError,pszError); + + return; +} + + +void SAL_CALL osl_psz_getLastSocketErrorDescription(oslSocket pSocket, sal_Char* pBuffer, sal_uInt32 BufferSize) +{ + /* make shure pBuffer will be a zero-terminated string even when strncpy has to cut */ + pBuffer[BufferSize-1]= '\0'; + + if ( pSocket == 0 ) + { + strncpy(pBuffer, strerror(EINVAL), BufferSize-1); + return; + } + + strncpy(pBuffer, strerror(pSocket->m_nLastError), BufferSize-1); + return; +} + +/*****************************************************************************/ +/* osl_getLastSocketError */ +/*****************************************************************************/ +oslSocketError SAL_CALL osl_getLastSocketError(oslSocket pSocket) +{ + if ( pSocket == 0 ) + { + return ERROR_FROM_NATIVE(EINVAL); + } + + return ERROR_FROM_NATIVE(pSocket->m_nLastError); +} + +/*****************************************************************************/ +/* SocketSet */ +/*****************************************************************************/ +typedef struct _TSocketSetImpl +{ + int m_MaxHandle; /* for select(), the largest descriptor in the set */ + fd_set m_Set; /* the set of descriptors */ + +} TSocketSetImpl; + +/*****************************************************************************/ +/* osl_createSocketSet */ +/*****************************************************************************/ +oslSocketSet SAL_CALL osl_createSocketSet() +{ + TSocketSetImpl* pSet; + + pSet= (TSocketSetImpl*)malloc(sizeof(TSocketSetImpl)); + + OSL_ASSERT(pSet); + + if(pSet) + { + pSet->m_MaxHandle= 0; + FD_ZERO(&pSet->m_Set); + } + + return (oslSocketSet)pSet; +} + +/*****************************************************************************/ +/* osl_destroySocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_destroySocketSet(oslSocketSet Set) +{ + if(Set) + free(Set); +} + +/*****************************************************************************/ +/* osl_clearSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_clearSocketSet(oslSocketSet Set) +{ + TSocketSetImpl* pSet; + OSL_ASSERT(Set); + if ( Set == 0 ) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + pSet->m_MaxHandle= 0; + + FD_ZERO(&pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_addToSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_addToSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + + if ( Set == 0 || pSocket == 0) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + + /* correct max handle */ + if(pSocket->m_Socket > pSet->m_MaxHandle) + pSet->m_MaxHandle= pSocket->m_Socket; + FD_SET(pSocket->m_Socket, &pSet->m_Set); + +} + +/*****************************************************************************/ +/* osl_removeFromSocketSet */ +/*****************************************************************************/ +void SAL_CALL osl_removeFromSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + + if ( Set == 0 || pSocket == 0) + { + return; + } + + pSet= (TSocketSetImpl*)Set; + + /* correct max handle */ + if(pSocket->m_Socket == pSet->m_MaxHandle) + { + /* not optimal, since the next used descriptor might be */ + /* much smaller than m_Socket-1, but it will do */ + pSet->m_MaxHandle--; + if(pSet->m_MaxHandle < 0) + { + pSet->m_MaxHandle= 0; /* avoid underflow */ + } + } + + FD_CLR(pSocket->m_Socket, &pSet->m_Set); +} + +/*****************************************************************************/ +/* osl_isInSocketSet */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isInSocketSet(oslSocketSet Set, oslSocket pSocket) +{ + TSocketSetImpl* pSet; + + OSL_ASSERT(Set); + OSL_ASSERT(pSocket); + if ( Set == 0 || pSocket == 0 ) + { + return sal_False; + } + + pSet= (TSocketSetImpl*)Set; + + return (FD_ISSET(pSocket->m_Socket, &pSet->m_Set) != 0); +} + +/*****************************************************************************/ +/* osl_demultiplexSocketEvents */ +/*****************************************************************************/ +sal_Int32 SAL_CALL osl_demultiplexSocketEvents(oslSocketSet IncomingSet, + oslSocketSet OutgoingSet, + oslSocketSet OutOfBandSet, + const TimeValue* pTimeout) +{ + int MaxHandle= 0; + struct timeval tv; + TSocketSetImpl* pInSet; + TSocketSetImpl* pOutSet; + TSocketSetImpl* pOOBSet; + + if (pTimeout) + { + /* non-blocking call */ + tv.tv_sec = pTimeout->Seconds; + tv.tv_usec = pTimeout->Nanosec / 1000L; + } + + /* map opaque data to impl-types */ + pInSet= (TSocketSetImpl*)IncomingSet; + pOutSet= (TSocketSetImpl*)OutgoingSet; + pOOBSet= (TSocketSetImpl*)OutOfBandSet; + + /* get max handle from all sets */ + if (pInSet) + MaxHandle= pInSet->m_MaxHandle; + + if (pOutSet && (pOutSet->m_MaxHandle > MaxHandle)) + MaxHandle= pOutSet->m_MaxHandle; + + if (pOOBSet && (pOOBSet->m_MaxHandle > MaxHandle)) + MaxHandle= pOOBSet->m_MaxHandle; + + return select(MaxHandle+1, + pInSet ? PTR_FD_SET(pInSet->m_Set) : 0, + pOutSet ? PTR_FD_SET(pOutSet->m_Set) : 0, + pOOBSet ? PTR_FD_SET(pOOBSet->m_Set) : 0, + pTimeout ? &tv : 0); +} + diff --git a/sal/osl/unx/sockimpl.h b/sal/osl/unx/sockimpl.h new file mode 100644 index 000000000000..86122e850875 --- /dev/null +++ b/sal/osl/unx/sockimpl.h @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OSL_SOCKETIMPL_H_ +#define _OSL_SOCKETIMPL_H_ + +#include <osl/pipe.h> +#include <osl/socket.h> +#include <osl/interlck.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (*oslCloseCallback) (void*); + +struct oslSocketImpl { + int m_Socket; + int m_nLastError; + oslCloseCallback m_CloseCallback; + void* m_CallbackArg; + oslInterlockedCount m_nRefCount; +#if defined(LINUX) + sal_Bool m_bIsAccepting; + sal_Bool m_bIsInShutdown; +#endif +}; + +struct oslSocketAddrImpl +{ + sal_Int32 m_nRefCount; + struct sockaddr m_sockaddr; +}; + +struct oslPipeImpl { + int m_Socket; + sal_Char m_Name[PATH_MAX + 1]; + oslInterlockedCount m_nRefCount; + sal_Bool m_bClosed; +#if defined(LINUX) + sal_Bool m_bIsAccepting; + sal_Bool m_bIsInShutdown; +#endif +}; + +oslSocket __osl_createSocketImpl(int Socket); +void __osl_destroySocketImpl(oslSocket pImpl); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sal/osl/unx/system.c b/sal/osl/unx/system.c new file mode 100644 index 000000000000..0ea3b819438c --- /dev/null +++ b/sal/osl/unx/system.c @@ -0,0 +1,599 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" + +#ifdef NO_PTHREAD_RTL + +static pthread_mutex_t getrtl_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* struct passwd differs on some platforms */ +#if defined NETBSD +struct passwd *getpwnam_r(const char* name, struct passwd* s, char* buffer, int size ) +{ + struct passwd* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = getpwnam(name)) ) + { + int nname, npasswd, nclass, ngecos, ndir; + + nname= strlen(res->pw_name)+1; + npasswd= strlen(res->pw_passwd)+1; + nclass= strlen(res->pw_class)+1; + ngecos= strlen(res->pw_gecos)+1; + ndir= strlen(res->pw_dir)+1; + + if (nname+npasswd+nclass+ngecos + +ndir+strlen(res->pw_shell) < size) + { + memcpy(s, res, sizeof(struct passwd)); + + strcpy(buffer, res->pw_name); + s->pw_name = buffer; + buffer += nname; + + strcpy(buffer, res->pw_passwd); + s->pw_passwd = buffer; + buffer += npasswd; + + strcpy(buffer, res->pw_class); + s->pw_class = buffer; + buffer += nclass; + + strcpy(buffer, res->pw_gecos); + s->pw_gecos = buffer; + buffer += ngecos; + + strcpy(buffer, res->pw_dir); + s->pw_dir = buffer; + buffer += ndir; + + strcpy(buffer, res->pw_shell); + s->pw_shell = buffer; + + res = s; + } + else + res = 0; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return(res); +} + +int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, + size_t buflen, struct passwd **result) +{ + struct passwd* res; + int retval = 0; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = getpwuid(uid)) ) + { + size_t pw_name, pw_passwd, pw_class, pw_gecos, pw_dir, pw_shell; + + pw_name = strlen(res->pw_name)+1; + pw_passwd = strlen(res->pw_passwd)+1; + pw_class = strlen(res->pw_class)+1; + pw_gecos = strlen(res->pw_gecos)+1; + pw_dir = strlen(res->pw_dir)+1; + pw_shell = strlen(res->pw_shell)+1; + + if (pw_name+pw_passwd+pw_class+pw_gecos + +pw_dir+pw_shell < buflen) + { + memcpy(pwd, res, sizeof(struct passwd)); + + strncpy(buffer, res->pw_name, pw_name); + pwd->pw_name = buffer; + buffer += pw_name; + + strncpy(buffer, res->pw_passwd, pw_passwd); + pwd->pw_passwd = buffer; + buffer += pw_passwd; + + strncpy(buffer, res->pw_class, pw_class); + pwd->pw_class = buffer; + buffer += pw_class; + + strncpy(buffer, res->pw_gecos, pw_gecos); + pwd->pw_gecos = buffer; + buffer += pw_gecos; + + strncpy(buffer, res->pw_dir, pw_dir); + pwd->pw_dir = buffer; + buffer += pw_dir; + + strncpy(buffer, res->pw_shell, pw_shell); + pwd->pw_shell = buffer; + buffer += pw_shell; + + *result = pwd ; + retval = 0 ; + + } + else + retval = ENOMEM; + } + else + retval = errno ; + + pthread_mutex_unlock(&getrtl_mutex); + + return retval; +} + +struct tm *localtime_r(const time_t *timep, struct tm *buffer) +{ + struct tm* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = localtime(timep))) + { + memcpy(buffer, res, sizeof(struct tm)); + res = buffer; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} + +struct tm *gmtime_r(const time_t *timep, struct tm *buffer) +{ + struct tm* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = gmtime(timep)) ) + { + memcpy(buffer, res, sizeof(struct tm)); + res = buffer; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} +#endif /* defined NETBSD */ + +#ifdef SCO +#include <pwd.h> +#include <shadow.h> +#include <sys/types.h> + +struct spwd *getspnam_r(const char *name, struct spwd* s, char* buffer, int size ) +{ + struct spwd* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( res = getspnam(name) ) + { + int nnamp; + + nnamp = strlen(res->sp_namp)+1; + + if (nnamp+strlen(res->sp_pwdp) < size) { + memcpy(s, res, sizeof(struct spwd)); + + strcpy(buffer, res->sp_namp); + s->sp_namp = buffer; + buffer += nnamp; + + strcpy(buffer, res->sp_pwdp); + s->sp_pwdp = buffer; + + res = s; + } + else + res = 0; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} + +struct passwd *getpwnam_r(const char* name, struct passwd* s, char* buffer, int size ) +{ + struct passwd* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( res = getpwnam(name) ) + { + int nname, npasswd, nage; + int ncomment, ngecos, ndir; + + nname= strlen(res->pw_name)+1; + npasswd= strlen(res->pw_passwd)+1; + nage= strlen(res->pw_age)+1; + ncomment= strlen(res->pw_comment)+1; + ngecos= strlen(res->pw_gecos)+1; + ndir= strlen(res->pw_dir)+1; + + if (nname+npasswd+nage+ncomment+ngecos+ndir + +strlen(res->pw_shell) < size) + { + memcpy(s, res, sizeof(struct passwd)); + + strcpy(buffer, res->pw_name); + s->pw_name = buffer; + buffer += nname; + + strcpy(buffer, res->pw_passwd); + s->pw_passwd = buffer; + buffer += npasswd; + + strcpy(buffer, res->pw_age); + s->pw_age = buffer; + buffer += nage; + + strcpy(buffer, res->pw_comment); + s->pw_comment = buffer; + buffer += ncomment; + + strcpy(buffer, res->pw_gecos); + s->pw_gecos = buffer; + buffer += ngecos; + + strcpy(buffer, res->pw_dir); + s->pw_dir = buffer; + buffer += ndir; + + strcpy(buffer, res->pw_shell); + s->pw_shell = buffer; + + res = s; + } + else + res = 0; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} +#endif /* defined SCO */ + +#if !defined(FREEBSD) || (__FreeBSD_version < 601103) + +extern int h_errno; + +struct hostent *gethostbyname_r(const char *name, struct hostent *result, + char *buffer, int buflen, int *h_errnop) +{ + /* buffer layout: name\0 + * array_of_pointer_to_aliases + * NULL + * alias1\0...aliasn\0 + * array_of_pointer_to_addresses + * NULL + * addr1addr2addr3...addrn + */ + struct hostent* res; + + pthread_mutex_lock(&getrtl_mutex); + + if ( (res = gethostbyname(name)) ) + { + int nname, naliases, naddr_list, naliasesdata, n; + char **p, **parray, *data; + + /* Check buffer size before copying, we want to leave the + * buffers unmodified in case something goes wrong. + * + * Is this required? + */ + + nname= strlen(res->h_name)+1; + + naliases = naddr_list = naliasesdata = 0; + + for ( p = res->h_aliases; *p != NULL; p++) { + naliases++; + naliasesdata += strlen(*p)+1; + } + + for ( p = res->h_addr_list; *p != NULL; p++) + naddr_list++; + + if ( nname + + (naliases+1)*sizeof(char*) + naliasesdata + + (naddr_list+1)*sizeof(char*) + naddr_list*res->h_length + <= buflen ) + { + memcpy(result, res, sizeof(struct hostent)); + + strcpy(buffer, res->h_name); + result->h_name = buffer; + buffer += nname; + + parray = (char**)buffer; + result->h_aliases = parray; + data = buffer + (naliases+1)*sizeof(char*); + for ( p = res->h_aliases; *p != NULL; p++) { + n = strlen(*p)+1; + *parray++ = data; + memcpy(data, *p, n); + data += n; + } + *parray = NULL; + buffer = data; + parray = (char**)buffer; + result->h_addr_list = parray; + data = buffer + (naddr_list+1)*sizeof(char*); + for ( p = res->h_addr_list; *p != NULL; p++) { + *parray++ = data; + memcpy(data, *p, res->h_length); + data += res->h_length; + } + *parray = NULL; + + res = result; + } + else + { + errno = ERANGE; + res = NULL; + } + } + else + { + *h_errnop = h_errno; + } + + pthread_mutex_unlock(&getrtl_mutex); + + return res; +} +#endif /* !defined(FREEBSD) || (__FreeBSD_version < 601103) */ + +#if defined(MACOSX) +/* + * Add support for resolving Mac native alias files (not the same as unix alias files) + * returns 0 on success. + */ +int macxp_resolveAlias(char *path, int buflen) +{ + FSRef aFSRef; + OSStatus nErr; + Boolean bFolder; + Boolean bAliased; + char *unprocessedPath = path; + + if ( *unprocessedPath == '/' ) + unprocessedPath++; + + int nRet = 0; + while ( !nRet && unprocessedPath && *unprocessedPath ) + { + unprocessedPath = strchr( unprocessedPath, '/' ); + if ( unprocessedPath ) + *unprocessedPath = '\0'; + + nErr = noErr; + bFolder = FALSE; + bAliased = FALSE; + if ( FSPathMakeRef( (const UInt8 *)path, &aFSRef, 0 ) == noErr ) + { + nErr = FSResolveAliasFileWithMountFlags( &aFSRef, TRUE, &bFolder, &bAliased, kResolveAliasFileNoUI ); + if ( nErr == nsvErr ) + { + errno = ENOENT; + nRet = -1; + } + else if ( nErr == noErr && bAliased ) + { + char tmpPath[ PATH_MAX ]; + if ( FSRefMakePath( &aFSRef, (UInt8 *)tmpPath, PATH_MAX ) == noErr ) + { + int nLen = strlen( tmpPath ) + ( unprocessedPath ? strlen( unprocessedPath + 1 ) + 1 : 0 ); + if ( nLen < buflen && nLen < PATH_MAX ) + { + if ( unprocessedPath ) + { + int nTmpPathLen = strlen( tmpPath ); + strcat( tmpPath, "/" ); + strcat( tmpPath, unprocessedPath + 1 ); + strcpy( path, tmpPath); + unprocessedPath = path + nTmpPathLen; + } + else if ( !unprocessedPath ) + { + strcpy( path, tmpPath); + } + } + else + { + errno = ENAMETOOLONG; + nRet = -1; + } + } + } + } + + if ( unprocessedPath ) + *unprocessedPath++ = '/'; + } + + return nRet; +} + +#endif /* defined MACOSX */ + +#endif /* NO_PTHREAD_RTL */ + +#if (defined (LINUX) && (GLIBC >= 2)) +/* The linux kernel thread implemention, always return the pid of the + thread subprocess and not of the main process. So we save the main + pid at startup +*/ + +// Directly from libc.so.6, obviously missing from some unistd.h: +extern __pid_t __getpid(void); + +static pid_t pid = -1; + +static void savePid(void) __attribute__((constructor)); + +static void savePid(void) +{ + if (pid == -1) + pid = __getpid(); +} + +pid_t getpid(void) +{ + if (pid == -1) + savePid(); + + return (pid); +} +#endif /* (defined (LINUX) && (GLIBC >= 2)) */ + +#ifdef NO_PTHREAD_SEMAPHORES +int sem_init(sem_t* sem, int pshared, unsigned int value) +{ + pthread_mutex_init(&sem->mutex, PTHREAD_MUTEXATTR_DEFAULT); + pthread_cond_init(&sem->increased, PTHREAD_CONDATTR_DEFAULT); + + sem->value = (int)value; + return 0; +} + +int sem_destroy(sem_t* sem) +{ + pthread_mutex_destroy(&sem->mutex); + pthread_cond_destroy(&sem->increased); + sem->value = 0; + return 0; +} + +int sem_wait(sem_t* sem) +{ + pthread_mutex_lock(&sem->mutex); + + while (sem->value <= 0) + { + pthread_cond_wait(&sem->increased, &sem->mutex); + } + + sem->value--; + pthread_mutex_unlock(&sem->mutex); + + return 0; +} + +int sem_trywait(sem_t* sem) +{ + int result = 0; + + pthread_mutex_lock(&sem->mutex); + + if (sem->value > 0) + { + sem->value--; + } + else + { + errno = EAGAIN; + result = -1; + } + + pthread_mutex_unlock(&sem->mutex); + + return result; +} + +int sem_post(sem_t* sem) +{ + pthread_mutex_lock(&sem->mutex); + + sem->value++; + + pthread_mutex_unlock(&sem->mutex); + + pthread_cond_signal(&sem->increased); + + return 0; +} +#endif + +#if defined(FREEBSD) +char *fcvt(double value, int ndigit, int *decpt, int *sign) +{ + static char ret[256]; + char buf[256],zahl[256],format[256]="%"; + char *v1,*v2; + + if (value==0.0) value=1e-30; + + if (value<0.0) *sign=1; else *sign=0; + + if (value<1.0) + { + *decpt=(int)log10(value); + value*=pow(10.0,1-*decpt); + ndigit+=*decpt-1; + if (ndigit<0) ndigit=0; + } + else + { + *decpt=(int)log10(value)+1; + } + + sprintf(zahl,"%d",ndigit); + strcat(format,zahl); + strcat(format,"."); + strcat(format,zahl); + strcat(format,"f"); + + sprintf(buf,format,value); + + if (ndigit!=0) + { + v1=strtok(buf,"."); + v2=strtok(NULL,"."); + strcpy(ret,v1); + strcat(ret,v2); + } + else + { + strcpy(ret,buf); + } + + return(ret); +} + +#endif diff --git a/sal/osl/unx/system.h b/sal/osl/unx/system.h new file mode 100644 index 000000000000..1cb0979490c0 --- /dev/null +++ b/sal/osl/unx/system.h @@ -0,0 +1,495 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __OSL_SYSTEM_H__ +#define __OSL_SYSTEM_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> + +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <signal.h> +#include <utime.h> + +#include <pwd.h> + +#include <netdb.h> + +#include <sys/stat.h> +#include <sys/wait.h> + +#include <sys/types.h> + +/* Make sockets of type AF_UNIX use underlying FS rights */ +#ifdef SOLARIS +# define _XOPEN_SOURCE 500 +# include <sys/socket.h> +# undef _XOPEN_SOURCE +#else +# include <sys/socket.h> +#endif + +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifdef SYSV +# include <sys/utsname.h> +#endif + +#ifdef LINUX +# ifndef __USE_GNU +# define __USE_GNU +# endif + +#if GLIBC >= 2 +# include <shadow.h> +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <sys/uio.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <dlfcn.h> +# include <endian.h> +# include <sys/time.h> +# include <semaphore.h> +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif __BYTE_ORDER == __BIG_ENDIAN +# ifndef _BIG_ENDIAN +# define _BIG_ENDIAN +# endif +# elif __BYTE_ORDER == __PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_PRIORITY +# define PTHREAD_SIGACTION pthread_sigaction +#else +# include <shadow.h> +# include <asm/sigcontext.h> +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <linux/net.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <linux/elfcore.h> +# include <dlfcn.h> +# include <endian.h> +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif __BYTE_ORDER == __BIG_ENDIAN +# define _BIG_ENDIAN +# elif __BYTE_ORDER == __PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_RTL +# define NO_PTHREAD_PRIORITY +# define PTHREAD_SIGACTION pthread_sigaction +#endif + +# ifndef ETIME +# define ETIME ETIMEDOUT +# endif + +#endif + +#ifdef NETBSD +# define ETIME ETIMEDOUT +# define _POSIX_THREAD_SYSCALL_SOFT 1 +# include <pthread.h> +# include <netdb.h> +# include <sys/sem.h> +# include <sys/exec.h> +# include <sys/filio.h> +# include <sys/ioctl.h> +# include <sys/time.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <dlfcn.h> +# include <machine/endian.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN_OO +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN_OO +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN_OO +# endif +# define IORESOURCE_TRANSFER_BSD +# define IOCHANNEL_TRANSFER_BSD_RENO +# define pthread_testcancel() +# define NO_PTHREAD_PRIORITY +# define NO_PTHREAD_SEMAPHORES +# define NO_PTHREAD_RTL +# define PTHREAD_SIGACTION pthread_sigaction +#endif + +#ifdef FREEBSD +# define ETIME ETIMEDOUT +# include <pthread.h> +# include <sys/sem.h> +# include <semaphore.h> +# include <dlfcn.h> +# include <sys/filio.h> +# include <sys/ioctl.h> +# include <sys/param.h> +# include <sys/time.h> +# include <sys/uio.h> +# include <sys/exec.h> +# include <vm/vm.h> +# include <vm/vm_param.h> +# include <vm/pmap.h> +# include <vm/swap_pager.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# define IORESOURCE_TRANSFER_BSD +# include <machine/endian.h> +#if __FreeBSD_version < 500000 +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +#endif +# define NO_PTHREAD_RTL +#endif + +#ifdef SCO +# define AF_IPX -1 +# include <strings.h> +# include <pthread.h> +# include <shadow.h> +# include <netdb.h> +# include <sys/un.h> +# include <sys/netinet/tcp.h> +# include <sys/types.h> +# include <sys/byteorder.h> +# include <dlfcn.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define sched_yield() pthread_yield() +# define pthread_testcancel() +# define NO_PTHREAD_RTL +# define NO_PTHREAD_PRIORITY +extern int pthread_cancel(pthread_t); +extern unsigned int nanosleep(unsigned int); +# define SLEEP_TIMESPEC(timespec) (timespec .tv_sec > 0) ? sleep(timespec .tv_sec), nanosleep(timespec .tv_nsec) : nanosleep(timespec .tv_nsec) +# define PATH_MAX _POSIX_PATH_MAX +# define S_ISSOCK S_ISFIFO +# define PTHREAD_SIGACTION pthread_sigaction +# define STAT_PARENT stat +#endif + +#ifdef AIX +# define AF_IPX -1 +# include <strings.h> +# include <pthread.h> +# include <sys/time.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <sys/machine.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# elif BYTE_ORDER == BIG_ENDIAN +# define _BIG_ENDIAN +# elif BYTE_ORDER == PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# define sched_yield() pthread_yield() +# define SLEEP_TIMESPEC(timespec) nsleep(×pec, 0) +# define LIBPATH "LIBPATH" +# define NO_PTHREAD_SEMAPHORES +# define NO_DL_FUNCTIONS +#endif + +#ifdef HPUX +# define AF_IPX -1 +# undef howmany +# undef MAXINT +# include <pthread.h> +# include <sys/un.h> +# include <sys/sched.h> +# include <sys/xti.h> +# include <sys/pstat.h> +# include <shadow.h> +# include <crypt.h> +# include <machine/param.h> +# define LIBPATH "SHLIB_PATH" +# define PTR_FD_SET(s) ((int *)&(s)) +# define PTHREAD_VALUE(t) ((t).field2) +# define PTHREAD_NONE_INIT { 0, -1 } +# define PTHREAD_ATTR_DEFAULT pthread_attr_default +# define PTHREAD_MUTEXATTR_DEFAULT pthread_mutexattr_default +# define PTHREAD_CONDATTR_DEFAULT pthread_condattr_default +# define pthread_detach(t) pthread_detach(&(t)) +# define NO_PTHREAD_PRIORITY +# define NO_PTHREAD_SEMAPHORES +# define NO_DL_FUNCTIONS +# undef sigaction +# define PTHREAD_SIGACTION cma_sigaction +#endif + +#ifdef SOLARIS +# include <shadow.h> +# include <sys/un.h> +# include <stropts.h> +# include <pthread.h> +# include <semaphore.h> +# include <netinet/tcp.h> +# include <sys/filio.h> +# include <dlfcn.h> +# include <sys/isa_defs.h> +# define IORESOURCE_TRANSFER_SYSV +# define IOCHANNEL_TRANSFER_BSD +# define LIBPATH "LD_LIBRARY_PATH" +#endif + +#ifdef MACOSX +#define __OPENTRANSPORTPROVIDERS__ // these are already defined +#define TimeValue CFTimeValue // Do not conflict with TimeValue in sal/inc/osl/time.h +#include <Carbon/Carbon.h> +#undef TimeValue +# ifndef ETIME +# define ETIME ETIMEDOUT +# endif +# include <dlfcn.h> +# include <pthread.h> +# include <sys/file.h> +# include <sys/ioctl.h> +# include <sys/uio.h> +# include <sys/un.h> +# include <netinet/tcp.h> +# include <machine/endian.h> +# include <sys/time.h> +# include <sys/semaphore.h> +/* fixme are premac and postmac still needed here? */ +# include <premac.h> +# include <mach-o/dyld.h> +# include <postmac.h> +# if BYTE_ORDER == LITTLE_ENDIAN +# ifndef _LITTLE_ENDIAN +# define _LITTLE_ENDIAN +# endif +# elif BYTE_ORDER == BIG_ENDIAN +# ifndef _BIG_ENDIAN +# define _BIG_ENDIAN +# endif +# elif BYTE_ORDER == PDP_ENDIAN +# ifndef _PDP_ENDIAN +# define _PDP_ENDIAN +# endif +# endif +# define IOCHANNEL_TRANSFER_BSD_RENO +# define NO_PTHREAD_RTL +/* for NSGetArgc/Argv/Environ */ +# include <crt_externs.h> +#ifdef __cplusplus +extern "C" { +#endif +int macxp_resolveAlias(char *path, int buflen); +#ifdef __cplusplus +} +#endif +#endif + +#if !defined(_WIN32) && !defined(_WIN16) && !defined(OS2) && \ + !defined(LINUX) && !defined(NETBSD) && !defined(FREEBSD) && !defined(SCO) && \ + !defined(AIX) && !defined(HPUX) && \ + !defined(SOLARIS) && !defined(MACOSX) +# error "Target platform not specified!" +#endif + +#if defined(NETBSD) +#if defined _LITTLE_ENDIAN_OO +# define _OSL_BIGENDIAN +#elif defined _BIG_ENDIAN_OO +# define _OSL_LITENDIAN +#else +# error undetermined endianess +#endif +#else +#if defined _LITTLE_ENDIAN +# define _OSL_BIGENDIAN +#elif defined _BIG_ENDIAN +# define _OSL_LITENDIAN +#else +# error undetermined endianess +#endif +#endif + +#ifndef PTR_FD_SET +# define PTR_FD_SET(s) (&(s)) +#endif + +#ifndef NORMALIZE_TIMESPEC +# define NORMALIZE_TIMESPEC(timespec) \ + timespec . tv_sec += timespec . tv_nsec / 1000000000; \ + timespec . tv_nsec %= 1000000000; +#endif + +#ifndef SET_TIMESPEC +# define SET_TIMESPEC(timespec, sec, nsec) \ + timespec . tv_sec = (sec); \ + timespec . tv_nsec = (nsec); \ + NORMALIZE_TIMESPEC(timespec); +#endif + +#ifndef SLEEP_TIMESPEC +# define SLEEP_TIMESPEC(timespec) nanosleep(×pec, 0) +#endif + +#ifndef INIT_GROUPS +# define INIT_GROUPS(name, gid) ((setgid((gid)) == 0) && (initgroups((name), (gid)) == 0)) +#endif + +#ifndef PTHREAD_VALUE +# define PTHREAD_VALUE(t) (t) +#endif +#ifndef PTHREAD_NONE +# if (__GNUC__ < 4) && !defined(MACOSX) +extern pthread_t _pthread_none_; +# endif +# define PTHREAD_NONE _pthread_none_ +# ifndef PTHREAD_NONE_INIT +# define PTHREAD_NONE_INIT ((pthread_t)-1) +# endif +#endif + +#ifndef PTHREAD_ATTR_DEFAULT +# define PTHREAD_ATTR_DEFAULT NULL +#endif +#ifndef PTHREAD_MUTEXATTR_DEFAULT +# define PTHREAD_MUTEXATTR_DEFAULT NULL +#endif +#ifndef PTHREAD_CONDATTR_DEFAULT +# define PTHREAD_CONDATTR_DEFAULT NULL +#endif + +#ifndef PTHREAD_SIGACTION +# define PTHREAD_SIGACTION sigaction +#endif + +#ifndef STAT_PARENT +# define STAT_PARENT lstat +#endif + +/* socket options which might not be defined on all unx flavors */ +#ifndef SO_ACCEPTCONN +# define SO_ACCEPTCONN 0 +#endif +#ifndef SO_SNDLOWAT +# define SO_SNDLOWAT 0 +#endif +#ifndef SO_RCVLOWAT +# define SO_RCVLOWAT 0 +#endif +#ifndef SO_SNDTIMEO +# define SO_SNDTIMEO 0 +#endif +#ifndef SO_RCVTIMEO +# define SO_RCVTIMEO 0 +#endif +#ifndef SO_USELOOPBACK +# define SO_USELOOPBACK 0 +#endif +#ifndef MSG_MAXIOVLEN +# define MSG_MAXIOVLEN 0 +#endif + +/* BEGIN HACK */ +/* dummy define and declarations for IPX should be replaced by */ +/* original ipx headers when these are available for this platform */ + +#ifndef SA_FAMILY_DECL +# define SA_FAMILY_DECL short sa_family +#endif + +typedef struct sockaddr_ipx { + SA_FAMILY_DECL; + char sa_netnum[4]; + char sa_nodenum[6]; + unsigned short sa_socket; +} SOCKADDR_IPX; + +#define NSPROTO_IPX 1000 +#define NSPROTO_SPX 1256 +#define NSPROTO_SPXII 1257 + +/* END HACK */ + +#ifdef NO_PTHREAD_SEMAPHORES + +typedef struct +{ + pthread_mutex_t mutex; + pthread_cond_t increased; + int value; +} sem_t; +extern int sem_init(sem_t* sem, int pshared, unsigned int value); +extern int sem_destroy(sem_t* sem); +extern int sem_wait(sem_t* sem); +extern int sem_trywait(sem_t* sem); +extern int sem_post(sem_t* sem); + +#endif + +#ifdef NO_PTHREAD_RTL +#if !defined FREEBSD || (__FreeBSD_version < 500112) +struct passwd *getpwent_r(struct passwd *pwd, char *buffer, int buflen); +extern struct spwd *getspnam_r(const char *name, struct spwd *result, + char *buffer, int buflen); + +struct tm *localtime_r(const time_t *timep, struct tm *buffer); +struct tm *gmtime_r(const time_t *timep, struct tm *buffer); +#endif /* !defined FREEBSD || (__FreeBSD_version < 500112) */ +#if !defined(FREEBSD) || (__FreeBSD_version < 601103) +struct hostent *gethostbyname_r(const char *name, struct hostent *result, + char *buffer, int buflen, int *h_errnop); +#endif /* !defined(FREEBSD) || (__FreeBSD_version < 601103) */ +#endif + +#endif /* __OSL_SYSTEM_H__ */ + diff --git a/sal/osl/unx/tempfile.c b/sal/osl/unx/tempfile.c new file mode 100644 index 000000000000..e10fffaa5ce2 --- /dev/null +++ b/sal/osl/unx/tempfile.c @@ -0,0 +1,370 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/*****************************************************************/ +/* Includes */ +/*****************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "system.h" +#include <osl/file.h> +#include <osl/thread.h> +#include <rtl/ustrbuf.h> +#include <osl/diagnose.h> + +#ifndef _FILE_URL_H_ +#include "file_url.h" +#endif + +/*****************************************************************/ +/* osl_getTempFirURL */ +/*****************************************************************/ + +oslFileError SAL_CALL osl_getTempDirURL( rtl_uString** pustrTempDir ) +{ +#ifdef MACOSX + const char *pValue = getenv( "TMPDIR" ); + + /* If TMPDIR environment variable is not set, use "/tmp" instead + of P_tmpdir because its value is "/var/tmp" and it is not + deleted on system start up */ + if ( !pValue ) + pValue = "/tmp"; +#else + + const char *pValue = getenv( "TEMP" ); + + if ( !pValue ) + { + pValue = getenv( "TMP" ); +#if defined(SOLARIS) || defined (LINUX) || defined (FREEBSD) + if ( !pValue ) + pValue = P_tmpdir; +#endif + } +#endif /* MACOSX */ + + if ( pValue ) + { + oslFileError error; + rtl_uString *ustrTempPath = NULL; + + rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(ustrTempPath != NULL); + error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir ); + rtl_uString_release( ustrTempPath ); + + return error; + } + else + return osl_File_E_NOENT; +} + +/****************************************************************** + * Generates a random unique file name. We're using the scheme + * from the standard c-lib function mkstemp to generate a more + * or less random unique file name + * + * @param rand_name + * receives the random name + ******************************************************************/ + +static const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; +static const int COUNT_OF_LETTERS = sizeof(LETTERS)/sizeof(LETTERS[0]) - 1; + +#define RAND_NAME_LENGTH 6 + +static void osl_gen_random_name_impl_(rtl_uString** rand_name) +{ + static uint64_t value; + + char buffer[RAND_NAME_LENGTH]; + struct timeval tv; + uint64_t v; + int i; + + gettimeofday(&tv, NULL); + + value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid(); + + v = value; + + for (i = 0; i < RAND_NAME_LENGTH; i++) + { + buffer[i] = LETTERS[v % COUNT_OF_LETTERS]; + v /= COUNT_OF_LETTERS; + } + + rtl_string2UString( + rand_name, + buffer, + RAND_NAME_LENGTH, + RTL_TEXTENCODING_ASCII_US, + OSTRING_TO_OUSTRING_CVTFLAGS); + OSL_ASSERT(*rand_name != NULL); +} + +/***************************************************************** + * Helper function + * Either use the directory provided or the result of + * osl_getTempDirUrl and return it as system path and file url + ****************************************************************/ + +static oslFileError osl_setup_base_directory_impl_( + rtl_uString* pustrDirectoryURL, + rtl_uString** ppustr_base_dir) +{ + rtl_uString* dir_url = 0; + rtl_uString* dir = 0; + oslFileError error = osl_File_E_None; + + if (pustrDirectoryURL) + rtl_uString_assign(&dir_url, pustrDirectoryURL); + else + error = osl_getTempDirURL(&dir_url); + + if (osl_File_E_None == error) + { + error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir, FURL_DENY_RELATIVE); + rtl_uString_release(dir_url); + } + + if (osl_File_E_None == error) + { + rtl_uString_assign(ppustr_base_dir, dir); + rtl_uString_release(dir); + } + + return error; +} + +/***************************************************************** + * osl_setup_createTempFile_impl + * validate input parameter, setup variables + ****************************************************************/ + + static oslFileError osl_setup_createTempFile_impl_( + rtl_uString* pustrDirectoryURL, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL, + rtl_uString** ppustr_base_dir, + sal_Bool* b_delete_on_close) + { + oslFileError osl_error; + + OSL_PRECOND(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!"); + + if ((0 == pHandle) && (0 == ppustrTempFileURL)) + { + osl_error = osl_File_E_INVAL; + } + else + { + osl_error = osl_setup_base_directory_impl_( + pustrDirectoryURL, ppustr_base_dir); + + *b_delete_on_close = (0 == ppustrTempFileURL); + } + + return osl_error; + } + +/***************************************************************** + * Create a unique file in the specified directory and return + * it's name + ****************************************************************/ + +static oslFileError osl_create_temp_file_impl_( + const rtl_uString* pustr_base_directory, + oslFileHandle* file_handle, + rtl_uString** ppustr_temp_file_name) +{ + rtl_uString* rand_name = 0; + sal_uInt32 len_base_dir = 0; + rtl_uString* tmp_file_path = 0; + rtl_uString* tmp_file_url = 0; + sal_Int32 capacity = 0; + oslFileError osl_error = osl_File_E_None; + sal_Int32 offset_file_name; + const sal_Unicode* puchr; + + OSL_PRECOND(pustr_base_directory, "Invalid Parameter"); + OSL_PRECOND(file_handle, "Invalid Parameter"); + OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter"); + + len_base_dir = rtl_uString_getLength(pustr_base_directory); + + rtl_uStringbuffer_newFromStr_WithLength( + &tmp_file_path, + rtl_uString_getStr((rtl_uString*)pustr_base_directory), + len_base_dir); + + rtl_uStringbuffer_ensureCapacity( + &tmp_file_path, + &capacity, + (len_base_dir + 1 + RAND_NAME_LENGTH)); + + offset_file_name = len_base_dir; + + puchr = rtl_uString_getStr(tmp_file_path); + + /* ensure that the last character is a '/' */ + + if ((sal_Unicode)'/' != puchr[len_base_dir - 1]) + { + rtl_uStringbuffer_insert_ascii( + &tmp_file_path, + &capacity, + len_base_dir, + "/", + 1); + + offset_file_name++; + } + + while(1) /* try until success */ + { + osl_gen_random_name_impl_(&rand_name); + + rtl_uStringbuffer_insert( + &tmp_file_path, + &capacity, + offset_file_name, + rtl_uString_getStr(rand_name), + rtl_uString_getLength(rand_name)); + + osl_error = osl_getFileURLFromSystemPath( + tmp_file_path, &tmp_file_url); + + if (osl_File_E_None == osl_error) + { + /* RW permission for the user only! */ + mode_t old_mode = umask(077); + + osl_error = osl_openFile( + tmp_file_url, + file_handle, + osl_File_OpenFlag_Read | + osl_File_OpenFlag_Write | + osl_File_OpenFlag_Create); + + umask(old_mode); + } + + /* in case of error osl_File_E_EXIST we simply try again else we give up */ + + if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST)) + { + if (rand_name) + rtl_uString_release(rand_name); + + if (tmp_file_url) + rtl_uString_release(tmp_file_url); + + break; + } + } /* while(1) */ + + if (osl_File_E_None == osl_error) + rtl_uString_assign(ppustr_temp_file_name, tmp_file_path); + + if (tmp_file_path) + rtl_uString_release(tmp_file_path); + + return osl_error; +} + +/***************************************************************** + * osl_createTempFile + *****************************************************************/ + +oslFileError SAL_CALL osl_createTempFile( + rtl_uString* pustrDirectoryURL, + oslFileHandle* pHandle, + rtl_uString** ppustrTempFileURL) +{ + rtl_uString* base_directory = 0; + rtl_uString* temp_file_name = 0; + oslFileHandle temp_file_handle; + sal_Bool b_delete_on_close; + oslFileError osl_error; + + osl_error = osl_setup_createTempFile_impl_( + pustrDirectoryURL, + pHandle, + ppustrTempFileURL, + &base_directory, + &b_delete_on_close); + + if (osl_File_E_None != osl_error) + return osl_error; + + osl_error = osl_create_temp_file_impl_( + base_directory, &temp_file_handle, &temp_file_name); + + if (osl_File_E_None == osl_error) + { + rtl_uString* temp_file_url = 0; + + /* assuming this works */ + osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url); + + if (b_delete_on_close) + { + osl_error = osl_removeFile(temp_file_url); + + if (osl_File_E_None == osl_error) + *pHandle = temp_file_handle; + else + osl_closeFile(temp_file_handle); + } + else + { + if (pHandle) + *pHandle = temp_file_handle; + else + osl_closeFile(temp_file_handle); + + rtl_uString_assign(ppustrTempFileURL, temp_file_url); + } + + if (temp_file_url) + rtl_uString_release(temp_file_url); + + if (temp_file_name) + rtl_uString_release(temp_file_name); + } + + if (base_directory) + rtl_uString_release(base_directory); + + return osl_error; +} diff --git a/sal/osl/unx/thread.c b/sal/osl/unx/thread.c new file mode 100644 index 000000000000..fe53915b792f --- /dev/null +++ b/sal/osl/unx/thread.c @@ -0,0 +1,1035 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "system.h" +#include <string.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/nlsupport.h> +#ifndef _RTL_TEXTENC_H_ +#include <rtl/textenc.h> +#endif + +/**************************************************************************** + * @@@ TODO @@@ + * + * (1) 'osl_thread_priority_init_Impl()' + * - insane assumption that initializing caller is main thread + * - use _POSIX_THREAD_PRIORITY_SCHEDULING, not NO_PTHREAD_PRIORITY (?) + * - POSIX doesn't require defined prio's for SCHED_OTHER (!) + * - use SCHED_RR instead of SCHED_OTHER for defined behaviour (?) + * (2) 'oslThreadIdentifier' and '{insert|remove|lookup}ThreadId()' + * - cannot reliably be applied to 'alien' threads; + * - memory leak for 'alien' thread 'HashEntry's; + * - use 'PTHREAD_VALUE(pthread_t)' as identifier instead (?) + * - if yes, change 'oslThreadIdentifier' to 'intptr_t' or similar + * (3) 'oslSigAlarmHandler()' (#71232#) + * - [Under Solaris we get SIGALRM in e.g. pthread_join which terminates + * the process. So we initialize our signal handling module and do + * register a SIGALRM Handler which catches and ignores it] + * - should this still happen, 'signal.c' needs to be fixed instead. + * + ****************************************************************************/ + +/*****************************************************************************/ +/* Internal data structures and functions */ +/*****************************************************************************/ + +#define THREADIMPL_FLAGS_TERMINATE 0x00001 +#define THREADIMPL_FLAGS_STARTUP 0x00002 +#define THREADIMPL_FLAGS_SUSPENDED 0x00004 +#define THREADIMPL_FLAGS_ACTIVE 0x00008 +#define THREADIMPL_FLAGS_ATTACHED 0x00010 +#define THREADIMPL_FLAGS_DESTROYED 0x00020 + +typedef struct osl_thread_impl_st +{ + pthread_t m_hThread; + sal_uInt16 m_Ident; /* @@@ see TODO @@@ */ + short m_Flags; + oslWorkerFunction m_WorkerFunction; + void* m_pData; + pthread_mutex_t m_Lock; + pthread_cond_t m_Cond; +} Thread_Impl; + +struct osl_thread_priority_st +{ + int m_Highest; + int m_Above_Normal; + int m_Normal; + int m_Below_Normal; + int m_Lowest; +}; + +#define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 } +static void osl_thread_priority_init_Impl (void); + +struct osl_thread_textencoding_st +{ + pthread_key_t m_key; /* key to store thread local text encoding */ + rtl_TextEncoding m_default; /* the default text encoding */ +}; + +#define OSL_THREAD_TEXTENCODING_INITIALIZER { 0, RTL_TEXTENCODING_DONTKNOW } +static void osl_thread_textencoding_init_Impl (void); + +struct osl_thread_global_st +{ + pthread_once_t m_once; + struct osl_thread_priority_st m_priority; + struct osl_thread_textencoding_st m_textencoding; +}; + +static struct osl_thread_global_st g_thread = +{ + PTHREAD_ONCE_INIT, + OSL_THREAD_PRIORITY_INITIALIZER, + OSL_THREAD_TEXTENCODING_INITIALIZER +}; + +static void osl_thread_init_Impl (void); + +static Thread_Impl* osl_thread_construct_Impl (void); +static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl); + +static void* osl_thread_start_Impl (void * pData); +static void osl_thread_cleanup_Impl (void * pData); + +static oslThread osl_thread_create_Impl ( + oslWorkerFunction pWorker, void * pThreadData, short nFlags); + +static void osl_thread_join_cleanup_Impl (void * opaque); +static void osl_thread_wait_cleanup_Impl (void * opaque); + +/* @@@ see TODO @@@ */ +static sal_uInt16 insertThreadId (pthread_t hThread); +static sal_uInt16 lookupThreadId (pthread_t hThread); +static void removeThreadId (pthread_t hThread); + +/*****************************************************************************/ +/* osl_thread_init_Impl */ +/*****************************************************************************/ +static void osl_thread_init_Impl (void) +{ + osl_thread_priority_init_Impl(); + osl_thread_textencoding_init_Impl(); +} + +/*****************************************************************************/ +/* osl_thread_join_cleanup_Impl */ +/*****************************************************************************/ +static void osl_thread_join_cleanup_Impl (void * opaque) +{ + pthread_t hThread = (pthread_t)(opaque); + pthread_detach (hThread); +} + +/*****************************************************************************/ +/* osl_thread_wait_cleanup_Impl */ +/*****************************************************************************/ +static void osl_thread_wait_cleanup_Impl (void * opaque) +{ + pthread_mutex_t * pMutex = (pthread_mutex_t*)(opaque); + pthread_mutex_unlock (pMutex); +} + +/*****************************************************************************/ +/* osl_thread_construct_Impl */ +/*****************************************************************************/ +Thread_Impl* osl_thread_construct_Impl (void) +{ + Thread_Impl* pImpl = malloc (sizeof(Thread_Impl)); + if (pImpl) + { + memset (pImpl, 0, sizeof(Thread_Impl)); + + pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT); + pthread_cond_init (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT); + } + return (pImpl); +} + +/*****************************************************************************/ +/* osl_thread_destruct_Impl */ +/*****************************************************************************/ +static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl) +{ + OSL_ASSERT(ppImpl); + if (*ppImpl) + { + pthread_cond_destroy (&((*ppImpl)->m_Cond)); + pthread_mutex_destroy (&((*ppImpl)->m_Lock)); + + free (*ppImpl); + (*ppImpl) = 0; + } +} + +/*****************************************************************************/ +/* osl_thread_cleanup_Impl */ +/*****************************************************************************/ +static void osl_thread_cleanup_Impl (void* pData) +{ + pthread_t thread; + int attached; + int destroyed; + Thread_Impl* pImpl= (Thread_Impl*)pData; + + pthread_mutex_lock (&(pImpl->m_Lock)); + + thread = pImpl->m_hThread; + attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0; + destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0; + pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + /* release oslThreadIdentifier @@@ see TODO @@@ */ + removeThreadId (thread); + + if (attached) + { + pthread_detach (thread); + } + + if (destroyed) + { + osl_thread_destruct_Impl (&pImpl); + } +} + +/*****************************************************************************/ +/* osl_thread_start_Impl */ +/*****************************************************************************/ +static void* osl_thread_start_Impl (void* pData) +{ + int terminate; + Thread_Impl* pImpl= (Thread_Impl*)pData; + + OSL_ASSERT(pImpl); + + pthread_mutex_lock (&(pImpl->m_Lock)); + + /* install cleanup handler */ + pthread_cleanup_push (osl_thread_cleanup_Impl, pData); + + /* request oslThreadIdentifier @@@ see TODO @@@ */ + pImpl->m_Ident = insertThreadId (pImpl->m_hThread); + + /* signal change from STARTUP to ACTIVE state */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP; + pImpl->m_Flags |= THREADIMPL_FLAGS_ACTIVE; + pthread_cond_signal (&(pImpl->m_Cond)); + + /* Check if thread is started in SUSPENDED state */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + pthread_cleanup_pop (0); + } + + /* check for SUSPENDED to TERMINATE state change */ + terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + if (!terminate) + { + /* call worker function */ + pImpl->m_WorkerFunction(pImpl->m_pData); + } + + /* call cleanup handler and leave */ + pthread_cleanup_pop (1); + return (0); +} + +/*****************************************************************************/ +/* osl_thread_create_Impl */ +/*****************************************************************************/ +static oslThread osl_thread_create_Impl ( + oslWorkerFunction pWorker, + void* pThreadData, + short nFlags) +{ + Thread_Impl* pImpl; + int nRet=0; + + pImpl = osl_thread_construct_Impl(); + if (!pImpl) + return (0); /* ENOMEM */ + + pImpl->m_WorkerFunction = pWorker; + pImpl->m_pData = pThreadData; + pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP; + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if ((nRet = pthread_create ( + &(pImpl->m_hThread), + PTHREAD_ATTR_DEFAULT, + osl_thread_start_Impl, + (void*)(pImpl))) != 0) + { + OSL_TRACE("osl_thread_create_Impl(): errno: %d, %s\n", + nRet, strerror(nRet)); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + osl_thread_destruct_Impl (&pImpl); + + return (0); + } + + /* wait for change from STARTUP to ACTIVE state */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP) + { + /* wait until STARTUP flag is cleared */ + pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + pthread_cleanup_pop (0); + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + return ((oslThread)(pImpl)); +} + +/*****************************************************************************/ +/* osl_createThread */ +/*****************************************************************************/ +oslThread osl_createThread ( + oslWorkerFunction pWorker, + void * pThreadData) +{ + return osl_thread_create_Impl ( + pWorker, + pThreadData, + THREADIMPL_FLAGS_ATTACHED); +} + +/*****************************************************************************/ +/* osl_createSuspendedThread */ +/*****************************************************************************/ +oslThread osl_createSuspendedThread ( + oslWorkerFunction pWorker, + void * pThreadData) +{ + return osl_thread_create_Impl ( + pWorker, + pThreadData, + THREADIMPL_FLAGS_ATTACHED | + THREADIMPL_FLAGS_SUSPENDED ); +} + +/*****************************************************************************/ +/* osl_destroyThread */ +/*****************************************************************************/ +void SAL_CALL osl_destroyThread(oslThread Thread) +{ + if (Thread != NULL) { + Thread_Impl * impl = (Thread_Impl *) Thread; + int active; + pthread_mutex_lock(&impl->m_Lock); + active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0; + impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED; + pthread_mutex_unlock(&impl->m_Lock); + if (!active) { + osl_thread_destruct_Impl(&impl); + } + } +} + +/*****************************************************************************/ +/* osl_resumeThread */ +/*****************************************************************************/ +void SAL_CALL osl_resumeThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* clear SUSPENDED flag */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED; + pthread_cond_signal (&(pImpl->m_Cond)); + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +/*****************************************************************************/ +/* osl_suspendThread */ +/*****************************************************************************/ +void SAL_CALL osl_suspendThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED; + + if (pthread_equal (pthread_self(), pImpl->m_hThread)) + { + /* self suspend */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + pthread_cleanup_pop (0); + } + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +/*****************************************************************************/ +/* osl_isThreadRunning */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread) +{ + sal_Bool active; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + if (!pImpl) + return sal_False; + + pthread_mutex_lock (&(pImpl->m_Lock)); + active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0); + pthread_mutex_unlock (&(pImpl->m_Lock)); + + return (active); +} + +/*****************************************************************************/ +/* osl_joinWithThread */ +/*****************************************************************************/ +void SAL_CALL osl_joinWithThread(oslThread Thread) +{ + pthread_t thread; + int attached; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + if (!pImpl) + return; + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pthread_equal (pthread_self(), pImpl->m_hThread)) + { + /* self join */ + pthread_mutex_unlock (&(pImpl->m_Lock)); + return; /* EDEADLK */ + } + + thread = pImpl->m_hThread; + attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0); + pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED; + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + if (attached) + { + /* install cleanup handler to ensure consistent flags and state */ + pthread_cleanup_push ( + osl_thread_join_cleanup_Impl, (void*)thread); + + /* join */ + pthread_join (thread, NULL); + + /* remove cleanup handler */ + pthread_cleanup_pop (0); + } +} + +/*****************************************************************************/ +/* osl_terminateThread */ +/*****************************************************************************/ +void SAL_CALL osl_terminateThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* clear SUSPENDED flag */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED; + pthread_cond_signal (&(pImpl->m_Cond)); + } + + pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE; + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +/*****************************************************************************/ +/* osl_scheduleThread */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread) +{ + int terminate; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return sal_False; /* EINVAL */ + + OSL_ASSERT(pthread_equal (pthread_self(), pImpl->m_hThread)); + if (!(pthread_equal (pthread_self(), pImpl->m_hThread))) + return sal_False; /* EINVAL */ + + pthread_testcancel(); + pthread_mutex_lock (&(pImpl->m_Lock)); + + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + pthread_cleanup_pop (0); + } + + terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0); + + pthread_mutex_unlock(&(pImpl->m_Lock)); + pthread_testcancel(); + + return (terminate == 0); +} + +/*****************************************************************************/ +/* osl_waitThread */ +/*****************************************************************************/ +void SAL_CALL osl_waitThread(const TimeValue* pDelay) +{ + if (pDelay) + { + struct timespec delay; + + SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec); + + SLEEP_TIMESPEC(delay); + } +} + +/*****************************************************************************/ +/* osl_yieldThread */ +/* + Note that POSIX scheduling _really_ requires threads to call this + functions, since a thread only reschedules to other thread, when + it blocks (sleep, blocking I/O) OR calls sched_yield(). +*/ +/*****************************************************************************/ +void SAL_CALL osl_yieldThread() +{ + sched_yield(); +} + +/*****************************************************************************/ +/* osl_getThreadIdentifier @@@ see TODO @@@ */ +/*****************************************************************************/ + +#define HASHID(x) ((unsigned int)PTHREAD_VALUE(x) % HashSize) + +typedef struct _HashEntry +{ + pthread_t Handle; + sal_uInt16 Ident; + struct _HashEntry *Next; +} HashEntry; + +static HashEntry* HashTable[31]; +static int HashSize = sizeof(HashTable) / sizeof(HashTable[0]); + +static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER; + +static sal_uInt16 LastIdent = 0; + +static sal_uInt16 lookupThreadId (pthread_t hThread) +{ + HashEntry *pEntry; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + { + pthread_mutex_unlock(&HashLock); + return (pEntry->Ident); + } + pEntry = pEntry->Next; + } + + pthread_mutex_unlock(&HashLock); + + return (0); +} + +static sal_uInt16 insertThreadId (pthread_t hThread) +{ + HashEntry *pEntry, *pInsert = NULL; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + break; + + pInsert = pEntry; + pEntry = pEntry->Next; + } + + if (pEntry == NULL) + { + pEntry = (HashEntry*) calloc(sizeof(HashEntry), 1); + + pEntry->Handle = hThread; + + ++ LastIdent; + + if ( LastIdent == 0 ) + LastIdent = 1; + + pEntry->Ident = LastIdent; + + if (pInsert) + pInsert->Next = pEntry; + else + HashTable[HASHID(hThread)] = pEntry; + } + + pthread_mutex_unlock(&HashLock); + + return (pEntry->Ident); +} + +static void removeThreadId (pthread_t hThread) +{ + HashEntry *pEntry, *pRemove = NULL; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + break; + + pRemove = pEntry; + pEntry = pEntry->Next; + } + + if (pEntry != NULL) + { + if (pRemove) + pRemove->Next = pEntry->Next; + else + HashTable[HASHID(hThread)] = pEntry->Next; + + free(pEntry); + } + + pthread_mutex_unlock(&HashLock); +} + +oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + sal_uInt16 Ident; + + if (pImpl) + Ident = pImpl->m_Ident; + else + { + /* current thread */ + pthread_t current = pthread_self(); + + Ident = lookupThreadId (current); + if (Ident == 0) + /* @@@ see TODO: alien pthread_self() @@@ */ + Ident = insertThreadId (current); + } + + return ((oslThreadIdentifier)(Ident)); +} + +/***************************************************************************** + @@@ see TODO @@@ + osl_thread_priority_init_Impl + + set the base-priority of the main-thread to + oslThreadPriorityNormal (64) since 0 (lowest) is + the system default. This behaviour collides with + our enum-priority definition (highest..normal..lowest). + A normaluser will expect the main-thread of an app. + to have the "normal" priority. + +*****************************************************************************/ +static void osl_thread_priority_init_Impl (void) +{ +#ifndef NO_PTHREAD_PRIORITY + struct sched_param param; + int policy=0; + int nRet=0; + +/* @@@ see TODO: calling thread may not be main thread @@@ */ + + if ((nRet = pthread_getschedparam(pthread_self(), &policy, ¶m)) != 0) + { + OSL_TRACE("failed to get priority of thread [%s]\n",strerror(nRet)); + return; + } + +#if defined (SOLARIS) + if ( policy >= _SCHED_NEXT) + { + /* mfe: pthread_getschedparam on Solaris has a possible Bug */ + /* one gets 959917873 as the policy */ + /* so set the policy to a default one */ + policy=SCHED_OTHER; + } +#endif /* SOLARIS */ + + if ((nRet = sched_get_priority_min(policy) ) != -1) + { + OSL_TRACE("Min Prioriy for policy '%i' == '%i'\n",policy,nRet); + g_thread.m_priority.m_Lowest=nRet; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + fprintf(stderr,"failed to get min sched param [%s]\n",strerror(errno)); + } +#endif /* OSL_DEBUG_LEVEL */ + + if ((nRet = sched_get_priority_max(policy) ) != -1) + { + OSL_TRACE("Max Prioriy for policy '%i' == '%i'\n",policy,nRet); + g_thread.m_priority.m_Highest=nRet; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + fprintf(stderr,"failed to get max sched param [%s]\n",strerror(errno)); + } +#endif /* OSL_DEBUG_LEVEL */ + + g_thread.m_priority.m_Normal = + (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2; + g_thread.m_priority.m_Below_Normal = + (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal) / 2; + g_thread.m_priority.m_Above_Normal = + (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2; + +/* @@@ set prio of calling (not main) thread (?) @@@ */ + + param.sched_priority= g_thread.m_priority.m_Normal; + + if ((nRet = pthread_setschedparam(pthread_self(), policy, ¶m)) != 0) + { + OSL_TRACE("failed to change base priority of thread [%s]\n",strerror(nRet)); + OSL_TRACE("Thread ID '%i', Policy '%i', Priority '%i'\n",pthread_self(),policy,param.sched_priority); + } + +#endif /* NO_PTHREAD_PRIORITY */ +} + +/*****************************************************************************/ +/* osl_setThreadPriority */ +/* + Impl-Notes: contrary to solaris-docu, which claims + valid priority-levels from 0 .. INT_MAX, only the + range 0..127 is accepted. (0 lowest, 127 highest) +*/ +/*****************************************************************************/ +void SAL_CALL osl_setThreadPriority ( + oslThread Thread, + oslThreadPriority Priority) +{ +#ifndef NO_PTHREAD_PRIORITY + + struct sched_param Param; + int policy; + int nRet; + +#endif /* NO_PTHREAD_PRIORITY */ + + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + +#ifdef NO_PTHREAD_PRIORITY + (void) Priority; /* unused */ +#else /* NO_PTHREAD_PRIORITY */ + + if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0) + return; /* ESRCH */ + +#if defined (SOLARIS) + if ( policy >= _SCHED_NEXT) + { + /* mfe: pthread_getschedparam on Solaris has a possible Bug */ + /* one gets 959917873 as the policy */ + /* so set the policy to a default one */ + policy=SCHED_OTHER; + } +#endif /* SOLARIS */ + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + switch(Priority) + { + case osl_Thread_PriorityHighest: + Param.sched_priority= g_thread.m_priority.m_Highest; + break; + + case osl_Thread_PriorityAboveNormal: + Param.sched_priority= g_thread.m_priority.m_Above_Normal; + break; + + case osl_Thread_PriorityNormal: + Param.sched_priority= g_thread.m_priority.m_Normal; + break; + + case osl_Thread_PriorityBelowNormal: + Param.sched_priority= g_thread.m_priority.m_Below_Normal; + break; + + case osl_Thread_PriorityLowest: + Param.sched_priority= g_thread.m_priority.m_Lowest; + break; + + case osl_Thread_PriorityUnknown: + OSL_ASSERT(sal_False); /* only fools try this...*/ + + /* let release-version behave friendly */ + return; + + default: + /* enum expanded, but forgotten here...*/ + OSL_ENSURE(sal_False,"osl_setThreadPriority : unknown priority\n"); + + /* let release-version behave friendly */ + return; + } + + if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0) + { + OSL_TRACE("failed to change thread priority [%s]\n",strerror(nRet)); + } + +#endif /* NO_PTHREAD_PRIORITY */ +} + +/*****************************************************************************/ +/* osl_getThreadPriority */ +/*****************************************************************************/ +oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread) +{ +#ifndef NO_PTHREAD_PRIORITY + + struct sched_param Param; + int Policy; + +#endif /* NO_PTHREAD_PRIORITY */ + + oslThreadPriority Priority = osl_Thread_PriorityNormal; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return osl_Thread_PriorityUnknown; /* EINVAL */ + +#ifndef NO_PTHREAD_PRIORITY + + if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0) + return osl_Thread_PriorityUnknown; /* ESRCH */ + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + /* map pthread priority to enum */ + if (Param.sched_priority==g_thread.m_priority.m_Highest) + { + /* 127 - highest */ + Priority= osl_Thread_PriorityHighest; + } + else if (Param.sched_priority > g_thread.m_priority.m_Normal) + { + /* 65..126 - above normal */ + Priority= osl_Thread_PriorityAboveNormal; + } + else if (Param.sched_priority == g_thread.m_priority.m_Normal) + { + /* normal */ + Priority= osl_Thread_PriorityNormal; + } + else if (Param.sched_priority > g_thread.m_priority.m_Lowest) + { + /* 63..1 -below normal */ + Priority= osl_Thread_PriorityBelowNormal; + } + else if (Param.sched_priority == g_thread.m_priority.m_Lowest) + { + /* 0 - lowest */ + Priority= osl_Thread_PriorityLowest; + } + else + { + /* unknown */ + Priority= osl_Thread_PriorityUnknown; + } + +#endif /* NO_PTHREAD_PRIORITY */ + + return Priority; +} + +/*****************************************************************************/ +/* osl_createThreadKey */ +/*****************************************************************************/ +oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback ) +{ + pthread_key_t key; + + if (pthread_key_create(&key, pCallback) != 0) + key = 0; + + return ((oslThreadKey)key); +} + +/*****************************************************************************/ +/* osl_destroyThreadKey */ +/*****************************************************************************/ +void SAL_CALL osl_destroyThreadKey(oslThreadKey Key) +{ + pthread_key_delete((pthread_key_t)Key); +} + +/*****************************************************************************/ +/* osl_getThreadKeyData */ +/*****************************************************************************/ +void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key) +{ + return (pthread_getspecific((pthread_key_t)Key)); +} + +/*****************************************************************************/ +/* osl_setThreadKeyData */ +/*****************************************************************************/ +sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData) +{ + return (pthread_setspecific((pthread_key_t)Key, pData) == 0); +} + +/*****************************************************************************/ +/* Thread Local Text Encoding */ +/*****************************************************************************/ +static void osl_thread_textencoding_init_Impl (void) +{ + rtl_TextEncoding defaultEncoding; + const char * pszEncoding; + + /* create thread specific data key */ + pthread_key_create (&(g_thread.m_textencoding.m_key), NULL); + + /* determine default text encoding */ + pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING"); + if (pszEncoding) + defaultEncoding = atoi(pszEncoding); + else + defaultEncoding = osl_getTextEncodingFromLocale(NULL); + + OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW); + + /* + Tools string functions call abort() on an unknown encoding so ASCII + is a meaningfull fallback regardless wether the assertion makes sense. + */ + + if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding ) + defaultEncoding = RTL_TEXTENCODING_ASCII_US; + + g_thread.m_textencoding.m_default = defaultEncoding; +} + +/*****************************************************************************/ +/* osl_getThreadTextEncoding */ +/*****************************************************************************/ +rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding() +{ + rtl_TextEncoding threadEncoding; + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + /* check for thread specific encoding, use default if not set */ + threadEncoding = SAL_INT_CAST( + rtl_TextEncoding, + (sal_uIntPtr) pthread_getspecific(g_thread.m_textencoding.m_key)); + if (0 == threadEncoding) + threadEncoding = g_thread.m_textencoding.m_default; + + return threadEncoding; +} + +/*****************************************************************************/ +/* osl_setThreadTextEncoding */ +/*****************************************************************************/ +rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding) +{ + rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding(); + + /* save encoding in thread local storage */ + pthread_setspecific ( + g_thread.m_textencoding.m_key, + (void*) SAL_INT_CAST(sal_uIntPtr, Encoding)); + + return oldThreadEncoding; +} diff --git a/sal/osl/unx/time.c b/sal/osl/unx/time.c new file mode 100644 index 000000000000..c1a98a6b87a9 --- /dev/null +++ b/sal/osl/unx/time.c @@ -0,0 +1,269 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "system.h" + +#include <osl/diagnose.h> +#include <osl/time.h> + +/* FIXME: detection should be done in configure script */ +#if defined(MACOSX) || defined(FREEBSD) || defined(NETBSD) || defined(LINUX) +#define STRUCT_TM_HAS_GMTOFF 1 + +#elif defined(SOLARIS) +#define HAS_ALTZONE 1 +#endif + +/*-------------------------------------------------- + * osl_getSystemTime + *-------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getSystemTime(TimeValue* TimeValue) +{ + struct timeval tp; + + /* FIXME: use higher resolution */ + gettimeofday(&tp, NULL); + + TimeValue->Seconds = tp.tv_sec; + TimeValue->Nanosec = tp.tv_usec * 1000; + + return (sal_True); +} + + +/*-------------------------------------------------- + * osl_getDateTimeFromTimeValue + *-------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getDateTimeFromTimeValue( TimeValue* pTimeVal, oslDateTime* pDateTime ) +{ + struct tm *pSystemTime; + struct tm tmBuf; + time_t atime; + + atime = (time_t)pTimeVal->Seconds; + + /* Convert time from type time_t to struct tm */ + pSystemTime = gmtime_r( &atime, &tmBuf ); + + + /* Convert struct tm to struct oslDateTime */ + if ( pSystemTime != NULL ) + { + pDateTime->NanoSeconds = pTimeVal->Nanosec; + pDateTime->Seconds = pSystemTime->tm_sec; + pDateTime->Minutes = pSystemTime->tm_min; + pDateTime->Hours = pSystemTime->tm_hour; + pDateTime->Day = pSystemTime->tm_mday; + pDateTime->DayOfWeek = pSystemTime->tm_wday; + pDateTime->Month = pSystemTime->tm_mon + 1; + pDateTime->Year = pSystemTime->tm_year + 1900; + + return sal_True; + } + + return sal_False; +} + +/*-------------------------------------------------- + * osl_getTimeValueFromDateTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getTimeValueFromDateTime( oslDateTime* pDateTime, TimeValue* pTimeVal ) +{ + struct tm aTime; + time_t nSeconds; + + /* Convert struct oslDateTime to struct tm */ + aTime.tm_sec = pDateTime->Seconds; + aTime.tm_min = pDateTime->Minutes; + aTime.tm_hour = pDateTime->Hours; + aTime.tm_mday = pDateTime->Day; + aTime.tm_wday = pDateTime->DayOfWeek; + + if ( pDateTime->Month > 0 ) + aTime.tm_mon = pDateTime->Month - 1; + else + return sal_False; + + if ( pDateTime->Year >= 1900 ) + aTime.tm_year = pDateTime->Year - 1900; + else + return sal_False; + + aTime.tm_isdst = -1; + aTime.tm_wday = 0; + aTime.tm_yday = 0; + + /* Convert time to calendar value */ + nSeconds = mktime( &aTime ); + + /* + * mktime expects the struct tm to be in local timezone, so we have to adjust + * the returned value to be timezone neutral. + */ + + if ( nSeconds != (time_t) -1 ) + { + time_t bias; + + /* timezone corrections */ + tzset(); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - aTime.tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = aTime.tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = aTime.tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + pTimeVal->Seconds = nSeconds; + pTimeVal->Nanosec = pDateTime->NanoSeconds; + + if ( nSeconds > bias ) + pTimeVal->Seconds -= bias; + + return sal_True; + } + + return sal_False; +} + + +/*-------------------------------------------------- + * osl_getLocalTimeFromSystemTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getLocalTimeFromSystemTime( TimeValue* pSystemTimeVal, TimeValue* pLocalTimeVal ) +{ + struct tm *pLocalTime; + struct tm tmBuf; + time_t bias; + time_t atime; + + atime = (time_t) pSystemTimeVal->Seconds; + pLocalTime = localtime_r( &atime, &tmBuf ); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - pLocalTime->tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = pLocalTime->tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = pLocalTime->tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + if ( (sal_Int64) pSystemTimeVal->Seconds > bias ) + { + pLocalTimeVal->Seconds = pSystemTimeVal->Seconds - bias; + pLocalTimeVal->Nanosec = pSystemTimeVal->Nanosec; + + return sal_True; + } + + return sal_False; +} + +/*-------------------------------------------------- + * osl_getSystemTimeFromLocalTime + *--------------------------------------------------*/ + +sal_Bool SAL_CALL osl_getSystemTimeFromLocalTime( TimeValue* pLocalTimeVal, TimeValue* pSystemTimeVal ) +{ + struct tm *pLocalTime; + struct tm tmBuf; + time_t bias; + time_t atime; + + atime = (time_t) pLocalTimeVal->Seconds; + + /* Convert atime, which is a local time, to it's GMT equivalent. Then, get + * the timezone offset for the local time for the GMT equivalent time. Note + * that we cannot directly use local time to determine the timezone offset + * because GMT is the only reliable time that we can determine timezone + * offset from. + */ + + atime = mktime( gmtime_r( &atime, &tmBuf ) ); + pLocalTime = localtime_r( &atime, &tmBuf ); + +#if defined(STRUCT_TM_HAS_GMTOFF) + /* members of struct tm are corrected by mktime */ + bias = 0 - pLocalTime->tm_gmtoff; + +#elif defined(HAS_ALTZONE) + /* check if daylight saving time is in effect */ + bias = pLocalTime->tm_isdst > 0 ? altzone : timezone; +#else + /* exspect daylight saving time to be one hour */ + bias = pLocalTime->tm_isdst > 0 ? timezone - 3600 : timezone; +#endif + + if ( (sal_Int64) pLocalTimeVal->Seconds + bias > 0 ) + { + pSystemTimeVal->Seconds = pLocalTimeVal->Seconds + bias; + pSystemTimeVal->Nanosec = pLocalTimeVal->Nanosec; + + return sal_True; + } + + return sal_False; +} + + + +static struct timeval startTime; +static sal_Bool bGlobalTimer = sal_False; + +sal_uInt32 SAL_CALL osl_getGlobalTimer() +{ + struct timeval currentTime; + sal_uInt32 nSeconds; + + // FIXME: not thread safe !! + if ( bGlobalTimer == sal_False ) + { + gettimeofday( &startTime, NULL ); + bGlobalTimer=sal_True; + } + + gettimeofday( ¤tTime, NULL ); + + nSeconds = (sal_uInt32)( currentTime.tv_sec - startTime.tv_sec ); + + return ( nSeconds * 1000 ) + (long) (( currentTime.tv_usec - startTime.tv_usec) / 1000 ); +} diff --git a/sal/osl/unx/util.c b/sal/osl/unx/util.c new file mode 100644 index 000000000000..5ba04db56021 --- /dev/null +++ b/sal/osl/unx/util.c @@ -0,0 +1,350 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef SOLARIS +#include <sys/sockio.h> +#endif + +#include "osl/util.h" + + + +/*****************************************************************************/ +/* Static Module Functions */ +/*****************************************************************************/ + +static int osl_getHWAddr(const char *ifname, char* hard_addr); +static int osl_checkAddr(const char* addr); + + +/*****************************************************************************/ +/* osl_getEthernetAddress */ +/*****************************************************************************/ + +sal_Bool SAL_CALL osl_getEthernetAddress( sal_uInt8 * pAddr ) +{ + char buff[1024]; + char hard_addr[64]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + int so; + +#ifdef SOLARIS + /** algorithm doesn't work on solaris */ + return sal_False; +#else + + if ( pAddr == 0 ) + { + return sal_False; + } + + + /* + * All we need is ... a network file descriptor. + * Normally, this is a very socket. + */ + + so = socket(AF_INET, SOCK_DGRAM, 0); + + + /* + * The first thing we have to do, get the interface configuration. + * It is a list of attached/configured interfaces + */ + + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if ( ioctl(so, SIOCGIFCONF, &ifc) < 0 ) + { +/* fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));*/ + close(so); + return sal_False; + } + + close(so); + + /* + * For each of the interfaces in the interface list, + * try to get the hardware address + */ + + ifr = ifc.ifc_req; + for ( i = ifc.ifc_len / sizeof(struct ifreq) ; --i >= 0 ; ifr++ ) + { + int nRet=0; + nRet = osl_getHWAddr(ifr->ifr_name,hard_addr); + if ( nRet > 0 ) + { + memcpy( pAddr , hard_addr, 6 ); + return sal_True; + } + } + + return sal_False; +#endif +} + + +/*****************************************************************************/ +/* osl_getHWAddr */ +/*****************************************************************************/ + +static int osl_getHWAddr(const char *ifname, char* hard_addr) +{ + int ret=0; + struct ifreq ifr; + int so = socket(AF_INET, SOCK_DGRAM, 0); + + strcpy(ifr.ifr_name, ifname); + + /* + * First, get the Interface-FLAGS + */ + + ret=ioctl(so, SIOCGIFFLAGS, &ifr) ; + + if ( ret < 0 ) + { +/* fprintf(stderr, "SIOCGIFFLAGS: %s\n", strerror(errno)); */ + close(so); + return ret; + } + + + /* + * If it is the loopback device, do not consider it any further + */ + + if (ifr.ifr_flags & IFF_LOOPBACK) + { +/* fprintf(stderr, "SIOCGIFFLAGS : is LOOPBACK : %s\n", strerror(errno));*/ + close(so); + return 0; + } + + + /* + * And now, the real thing: the get address + */ + +#ifdef SIOCGIFHWADDR + ret=ioctl(so, SIOCGIFHWADDR, &ifr); +#else + ret=ioctl(so, SIOCGIFADDR, &ifr); +#endif + + if (ret < 0) { +/* fprintf(stderr, "SIOCGIFADDR: %s\n", strerror(errno));*/ + memset(hard_addr, 0, 32); + close(so); + return ret; + } + + close(so); + +#ifdef SIOCGIFHWADDR + memcpy(hard_addr,ifr.ifr_hwaddr.sa_data,8); +#else + memcpy(hard_addr,ifr.ifr_ifru.ifru_addr.sa_data,8); +#endif + + + /* + * Check, if no real, i.e. 00:00:00:00:00:00, address was retrieved. + * The Linux dummy device has this kind of behaviour + */ + + ret=osl_checkAddr(hard_addr); + + if (ret < 0) { +/* fprintf(stderr, "SIOCGIFADDR got '00:00:00:00:00:00'\n"); */ + return ret; + } + +/* fprintf(stderr,"interface : %s -- ",ifname);*/ +/* fprintf(stderr,"HWaddr : %s\n", print_ether(hard_addr));*/ + + return 1; +} + + +/*****************************************************************************/ +/* osl_checkAddr */ +/*****************************************************************************/ + +static int osl_checkAddr(const char* addr) +{ + if (addr[0]==0 && addr[1]==0 && + addr[2]==0 && addr[3]==0 && + addr[4]==0 && addr[5]==0) + { + return -1; + } + return 0; +} + + +#if defined (SPARC) + +#if defined (SOLARIS) && !defined(__sparcv8plus) && !defined(__sparcv9) +#include <sys/types.h> +#include <sys/processor.h> + +/*****************************************************************************/ +/* osl_InitSparcV9 */ +/*****************************************************************************/ + +void osl_InterlockedCountSetV9(sal_Bool bV9); + +/* + * osl_InitSparcV9() should be executed as early as possible. We place it in the + * .init section of sal + */ +#if defined ( __SUNPRO_C ) || defined ( __SUNPRO_CC ) +void osl_InitSparcV9(void); +#pragma init (osl_InitSparcV9) +#elif defined ( __GNUC__ ) +void osl_InitSparcV9(void) __attribute__((constructor)); +#endif + +void osl_InitSparcV9(void) +{ + /* processor_info() identifies SPARCV8 (ie sun4c machines) simply as "sparc" + * and SPARCV9 (ie ultra sparcs, sun4u) as "sparcv9". Since we know that we + * run at least on a SPARCV8 architecture or better, any processor type != "sparc" + * and != "i386" is considered to be SPARCV9 or better + * + * This way we are certain that this will still work if someone names SPARCV10 + * "foobar" + */ + processor_info_t aInfo; + int rc; + + rc = processor_info(0, &aInfo); + + if ( rc != -1 ) { + if ( !strcmp( "sparc", aInfo.pi_processor_type ) /* SPARCV8 */ + || !strcmp( "i386", aInfo.pi_processor_type ) ) /* can't happen, but ... */ + return; + /* we are reasonably certain to be on sparcv9/sparcv8plus or better */ + osl_InterlockedCountSetV9(sal_True); + } +} + +#endif /* SOLARIS */ + +#if defined(NETBSD) && defined(GCC) && !defined(__sparcv9) && !defined(__sparc_v9__) + +#include <sys/param.h> +#include <sys/sysctl.h> +void osl_InitSparcV9(void) __attribute__((constructor)); +void osl_InterlockedCountSetV9(sal_Bool bV9); + +/* Determine which processor we are running on (sparc v8 or v9) + * The approach is very similar to Solaris. + */ + +void osl_InitSparcV9(void) +{ + int mib[2]={CTL_HW,HW_MACHINE}; + char processorname[256]; + size_t len=256; + + /* get the machine name */ + sysctl(mib, 2, processorname, &len, NULL, 0); + if (!strncmp("sparc64",processorname, len)) { + osl_InterlockedCountSetV9(sal_True); + } +} + +#endif /* NETBSD */ + +#endif /* SPARC */ + +#if defined ( LINUX ) && defined ( SPARC ) +#include <sys/utsname.h> +void osl_InitSparcV9(void) __attribute__((constructor)); +void osl_InterlockedCountSetV9(sal_Bool bV9); +/* Determine which processor we are running on (sparc v8 or v9) + * The approach is very similar to Solaris. + */ +void osl_InitSparcV9(void) +{ + struct utsname name; + int rc; + rc = uname(&name); + if ( rc != -1 ) { + if ( !strcmp( "sparc", name.machine )) + return; + osl_InterlockedCountSetV9(sal_True); + } +} +#endif + +#if ( defined(__GNUC__) && (defined(X86) || defined(X86_64)) )\ + || ( defined(SOLARIS) && defined (__SUNPRO_C) && defined(__i386) ) + +/* Safe default */ +int osl_isSingleCPU = 0; + +/* Determine if we are on a multiprocessor/multicore/HT x86/x64 system + * + * The lock prefix for atomic operations in osl_[inc|de]crementInterlockedCount() + * comes with a cost and is especially expensive on pre HT x86 single processor + * systems, where it isn't needed at all. + * + * This should be run as early as possible, thus it's placed in the init section + */ +#if defined(_SC_NPROCESSORS_CONF) /* i.e. MACOSX for Intel doesn't have this */ +#if defined(__GNUC__) +void osl_interlockedCountCheckForSingleCPU(void) __attribute__((constructor)); +#elif defined(__SUNPRO_C) +void osl_interlockedCountCheckForSingleCPU(void); +#pragma init (osl_interlockedCountCheckForSingleCPU) +#endif + +void osl_interlockedCountCheckForSingleCPU(void) +{ + /* In case sysconfig fails be on the safe side, + * consider it a multiprocessor/multicore/HT system */ + if ( sysconf(_SC_NPROCESSORS_CONF) == 1 ) { + osl_isSingleCPU = 1; + } +} +#endif /* defined(_SC_NPROCESSORS_CONF) */ +#endif diff --git a/sal/osl/unx/uunxapi.cxx b/sal/osl/unx/uunxapi.cxx new file mode 100644 index 000000000000..299ea4198fdc --- /dev/null +++ b/sal/osl/unx/uunxapi.cxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + + #ifndef _OSL_UUNXAPI_H_ + #include "uunxapi.h" + #endif + + #ifndef __OSL_SYSTEM_H__ + #include "system.h" + #endif + + #ifndef _LIMITS_H + #include <limits.h> + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + #ifndef _OSL_THREAD_H_ + #include <osl/thread.h> + #endif + + //########################### + inline rtl::OString OUStringToOString(const rtl_uString* s) + { + return rtl::OUStringToOString( + rtl::OUString(const_cast<rtl_uString*>(s)), + osl_getThreadTextEncoding()); + } + + //########################### +#ifdef MACOSX +/* + * Helper function for resolving Mac native alias files (not the same as unix alias files) + * and to return the resolved alias as rtl::OString + */ + inline rtl::OString macxp_resolveAliasAndConvert(const rtl_uString* s) + { + rtl::OString p = OUStringToOString(s); + sal_Char path[PATH_MAX]; + if (p.getLength() < PATH_MAX) + { + strcpy(path, p.getStr()); + macxp_resolveAlias(path, PATH_MAX); + p = rtl::OString(path); + } + return p; + } +#endif /* MACOSX */ + + //########################### + //access_u + int access_u(const rtl_uString* pustrPath, int mode) + { +#ifndef MACOSX // not MACOSX + return access(OUStringToOString(pustrPath).getStr(), mode); +#else + return access(macxp_resolveAliasAndConvert(pustrPath).getStr(), mode); +#endif + } + + //######################### + //realpath_u + sal_Bool realpath_u(const rtl_uString* pustrFileName, rtl_uString** ppustrResolvedName) + { +#ifndef MACOSX // not MACOSX + rtl::OString fn = OUStringToOString(pustrFileName); +#else + rtl::OString fn = macxp_resolveAliasAndConvert(pustrFileName); +#endif + char rp[PATH_MAX]; + bool bRet = realpath(fn.getStr(), rp); + + if (bRet) + { + rtl::OUString resolved = rtl::OStringToOUString( + rtl::OString(static_cast<sal_Char*>(rp)), + osl_getThreadTextEncoding()); + + rtl_uString_assign(ppustrResolvedName, resolved.pData); + } + return bRet; + } + + //######################### + //lstat_u + int lstat_u(const rtl_uString* pustrPath, struct stat* buf) + { +#ifndef MACOSX // not MACOSX + return lstat(OUStringToOString(pustrPath).getStr(), buf); +#else + return lstat(macxp_resolveAliasAndConvert(pustrPath).getStr(), buf); +#endif + } + + //######################### + // @see mkdir + int mkdir_u(const rtl_uString* path, mode_t mode) + { + return mkdir(OUStringToOString(path).getStr(), mode); + } + diff --git a/sal/osl/unx/uunxapi.h b/sal/osl/unx/uunxapi.h new file mode 100644 index 000000000000..9eddc5fe4753 --- /dev/null +++ b/sal/osl/unx/uunxapi.h @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_UUNXAPI_H_ + #define _OSL_UUNXAPI_H_ + + #ifndef _UNISTD_H + #include <unistd.h> + #endif + + #ifndef _STDLIB_H + #include <stdlib.h> + #endif + + #ifndef _TYPES_H + #include <sys/types.h> + #endif + + #ifndef _STAT_H + #include <sys/stat.h> + #endif + + #ifndef _RTL_USTRING_H_ + #include <rtl/ustring.h> + #endif + + + #ifdef __cplusplus + extern "C" + { + #endif + + /* @see access */ + int access_u(const rtl_uString* pustrPath, int mode); + + /*********************************** + @descr + The return value differs from the + realpath function + + @returns sal_True on success else + sal_False + + @see realpath + **********************************/ + sal_Bool realpath_u( + const rtl_uString* pustrFileName, + rtl_uString** ppustrResolvedName); + + /* @see lstat */ + int lstat_u(const rtl_uString* pustrPath, struct stat* buf); + + /* @see mkdir */ + int mkdir_u(const rtl_uString* path, mode_t mode); + + #ifdef __cplusplus + } + #endif + + + #endif /* _OSL_UUNXAPI_H_ */ + diff --git a/sal/osl/unx/uunxapi.hxx b/sal/osl/unx/uunxapi.hxx new file mode 100644 index 000000000000..7f1a9072e8cc --- /dev/null +++ b/sal/osl/unx/uunxapi.hxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + #ifndef _OSL_UUNXAPI_HXX_ + #define _OSL_UUNXAPI_HXX_ + + #ifndef _OSL_UUNXAPI_H_ + #include "uunxapi.h" + #endif + + #ifndef _RTL_USTRING_HXX_ + #include <rtl/ustring.hxx> + #endif + + namespace osl + { + + /*********************************** + osl::access + + @see access + **********************************/ + + inline int access(const rtl::OUString& ustrPath, int mode) + { + return access_u(ustrPath.pData, mode); + } + + /*********************************** + osl::realpath + + @descr + The return value differs from the + realpath function + + @returns sal_True on success else + sal_False + + @see realpath + **********************************/ + + inline sal_Bool realpath( + const rtl::OUString& ustrFileName, + rtl::OUString& ustrResolvedName) + { + return realpath_u(ustrFileName.pData, &ustrResolvedName.pData); + } + + + /*********************************** + osl::lstat + + @see lstat + **********************************/ + + inline int lstat(const rtl::OUString& ustrPath, struct stat& buf) + { + return lstat_u(ustrPath.pData, &buf); + } + + /*********************************** + osl::mkdir + @see mkdir + **********************************/ + inline int mkdir(const rtl::OUString& aPath, mode_t aMode) + { + return mkdir_u(aPath.pData, aMode); + } + + } // end namespace osl + + + #endif /* _OSL_UUNXAPI_HXX_ */ + |