/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: strmunx.cxx,v $ * $Revision: 1.15 $ * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // no include "precompiled_tools.hxx" because this file is included in strmsys.cxx #include #include #include #include #include #include #include #include // fuer getenv() #include #include #include #include #include // osl_getThreadTextEncoding // class FileBase #include #include using namespace osl; // ----------------------------------------------------------------------- // ---------------- // - InternalLock - // ---------------- class InternalStreamLock; DECLARE_LIST( InternalStreamLockList, InternalStreamLock* ) namespace { struct LockList : public rtl::Static< InternalStreamLockList, LockList > {}; } #ifndef BOOTSTRAP namespace { struct LockMutex : public rtl::Static< NAMESPACE_VOS(OMutex), LockMutex > {}; } #endif class InternalStreamLock { sal_Size m_nStartPos; sal_Size m_nEndPos; SvFileStream* m_pStream; struct stat m_aStat; InternalStreamLock( sal_Size, sal_Size, SvFileStream* ); ~InternalStreamLock(); public: static sal_Bool LockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* ); static void UnlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* ); }; InternalStreamLock::InternalStreamLock( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream ) : m_nStartPos( nStart ), m_nEndPos( nEnd ), m_pStream( pStream ) { ByteString aFileName(m_pStream->GetFileName(), osl_getThreadTextEncoding()); stat( aFileName.GetBuffer(), &m_aStat ); LockList::get().Insert( this, LIST_APPEND ); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "locked %s", aFileName.GetBuffer() ); if( m_nStartPos || m_nEndPos ) fprintf(stderr, " [ %d ... %d ]", m_nStartPos, m_nEndPos ); fprintf( stderr, "\n" ); #endif } InternalStreamLock::~InternalStreamLock() { LockList::get().Remove( this ); #if OSL_DEBUG_LEVEL > 1 ByteString aFileName(m_pStream->GetFileName(), osl_getThreadTextEncoding()); fprintf( stderr, "unlocked %s", aFileName.GetBuffer() ); if( m_nStartPos || m_nEndPos ) fprintf(stderr, " [ %d ... %d ]", m_nStartPos, m_nEndPos ); fprintf( stderr, "\n" ); #endif } sal_Bool InternalStreamLock::LockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream ) { #ifndef BOOTSTRAP NAMESPACE_VOS( OGuard ) aGuard( LockMutex::get() ); #endif ByteString aFileName(pStream->GetFileName(), osl_getThreadTextEncoding()); struct stat aStat; if( stat( aFileName.GetBuffer(), &aStat ) ) return sal_False; if( S_ISDIR( aStat.st_mode ) ) return sal_True; InternalStreamLock* pLock = NULL; InternalStreamLockList &rLockList = LockList::get(); for( ULONG i = 0; i < rLockList.Count(); ++i ) { pLock = rLockList.GetObject( i ); if( aStat.st_ino == pLock->m_aStat.st_ino ) { sal_Bool bDenyByOptions = sal_False; StreamMode nLockMode = pLock->m_pStream->GetStreamMode(); StreamMode nNewMode = pStream->GetStreamMode(); if( nLockMode & STREAM_SHARE_DENYALL ) bDenyByOptions = sal_True; else if( ( nLockMode & STREAM_SHARE_DENYWRITE ) && ( nNewMode & STREAM_WRITE ) ) bDenyByOptions = sal_True; else if( ( nLockMode & STREAM_SHARE_DENYREAD ) && ( nNewMode & STREAM_READ ) ) bDenyByOptions = sal_True; if( bDenyByOptions ) { if( pLock->m_nStartPos == 0 && pLock->m_nEndPos == 0 ) // whole file is already locked return sal_False; if( nStart == 0 && nEnd == 0) // cannot lock whole file return sal_False; if( ( nStart < pLock->m_nStartPos && nEnd > pLock->m_nStartPos ) || ( nStart < pLock->m_nEndPos && nEnd > pLock->m_nEndPos ) ) return sal_False; } } } pLock = new InternalStreamLock( nStart, nEnd, pStream ); return sal_True; } void InternalStreamLock::UnlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream ) { #ifndef BOOTSTRAP NAMESPACE_VOS( OGuard ) aGuard( LockMutex::get() ); #endif InternalStreamLock* pLock = NULL; InternalStreamLockList &rLockList = LockList::get(); if( nStart == 0 && nEnd == 0 ) { for( ULONG i = 0; i < rLockList.Count(); ++i ) { if( ( pLock = rLockList.GetObject( i ) )->m_pStream == pStream ) { delete pLock; i--; } } return; } for( ULONG i = 0; i < rLockList.Count(); ++i ) { if( ( pLock = rLockList.GetObject( i ) )->m_pStream == pStream && nStart == pLock->m_nStartPos && nEnd == pLock->m_nEndPos ) { delete pLock; return; } } } // -------------- // - StreamData - // -------------- class StreamData { public: int nHandle; StreamData() { nHandle = 0; } }; // ----------------------------------------------------------------------- static sal_uInt32 GetSvError( int nErrno ) { static struct { int nErr; sal_uInt32 sv; } errArr[] = { { 0, SVSTREAM_OK }, { EACCES, SVSTREAM_ACCESS_DENIED }, { EBADF, SVSTREAM_INVALID_HANDLE }, #if defined( RS6000 ) || defined( ALPHA ) || defined( HP9000 ) || defined( NETBSD ) || defined(FREEBSD) || defined(MACOSX) { EDEADLK, SVSTREAM_LOCKING_VIOLATION }, #else { EDEADLOCK, SVSTREAM_LOCKING_VIOLATION }, #endif { EINVAL, SVSTREAM_INVALID_PARAMETER }, { EMFILE, SVSTREAM_TOO_MANY_OPEN_FILES }, { ENFILE, SVSTREAM_TOO_MANY_OPEN_FILES }, { ENOENT, SVSTREAM_FILE_NOT_FOUND }, { EPERM, SVSTREAM_ACCESS_DENIED }, { EROFS, SVSTREAM_ACCESS_DENIED }, { EAGAIN, SVSTREAM_LOCKING_VIOLATION }, { EISDIR, SVSTREAM_PATH_NOT_FOUND }, { ELOOP, SVSTREAM_PATH_NOT_FOUND }, #if ! defined( RS6000 ) && ! defined( ALPHA ) && ! defined( NETBSD ) && ! defined (FREEBSD) && ! defined (MACOSX) { EMULTIHOP, SVSTREAM_PATH_NOT_FOUND }, { ENOLINK, SVSTREAM_PATH_NOT_FOUND }, #endif { ENOTDIR, SVSTREAM_PATH_NOT_FOUND }, { ETXTBSY, SVSTREAM_ACCESS_DENIED }, { EEXIST, SVSTREAM_CANNOT_MAKE }, { ENOSPC, SVSTREAM_DISK_FULL }, { (int)0xFFFF, SVSTREAM_GENERALERROR } }; sal_uInt32 nRetVal = SVSTREAM_GENERALERROR; // Standardfehler int i=0; do { if ( errArr[i].nErr == nErrno ) { nRetVal = errArr[i].sv; break; } ++i; } while( errArr[i].nErr != 0xFFFF ); return nRetVal; } /************************************************************************* |* |* SvFileStream::SvFileStream() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 08.06.94 |* Letzte Aenderung OV 08.06.94 |* *************************************************************************/ SvFileStream::SvFileStream( const String& rFileName, StreamMode nOpenMode ) { bIsOpen = sal_False; nLockCounter = 0; bIsWritable = sal_False; pInstanceData = new StreamData; SetBufferSize( 1024 ); // convert URL to SystemPath, if necessary ::rtl::OUString aSystemFileName; if( FileBase::getSystemPathFromFileURL( rFileName , aSystemFileName ) != FileBase::E_None ) { aSystemFileName = rFileName; } Open( aSystemFileName, nOpenMode ); } /************************************************************************* |* |* SvFileStream::SvFileStream() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 22.11.94 |* Letzte Aenderung OV 22.11.94 |* *************************************************************************/ SvFileStream::SvFileStream() { bIsOpen = sal_False; nLockCounter = 0; bIsWritable = sal_False; pInstanceData = new StreamData; SetBufferSize( 1024 ); } /************************************************************************* |* |* SvFileStream::~SvFileStream() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 22.11.94 |* Letzte Aenderung OV 22.11.94 |* *************************************************************************/ SvFileStream::~SvFileStream() { Close(); InternalStreamLock::UnlockFile( 0, 0, this ); if (pInstanceData) delete pInstanceData; } /************************************************************************* |* |* SvFileStream::GetFileHandle() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 22.11.94 |* Letzte Aenderung OV 22.11.94 |* *************************************************************************/ sal_uInt32 SvFileStream::GetFileHandle() const { return (sal_uInt32)pInstanceData->nHandle; } /************************************************************************* |* |* SvFileStream::IsA() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 14.06.94 |* Letzte Aenderung OV 14.06.94 |* *************************************************************************/ sal_uInt16 SvFileStream::IsA() const { return ID_FILESTREAM; } /************************************************************************* |* |* SvFileStream::GetData() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ sal_Size SvFileStream::GetData( void* pData, sal_Size nSize ) { #ifdef DBG_UTIL ByteString aTraceStr( "SvFileStream::GetData(): " ); aTraceStr += ByteString::CreateFromInt64(nSize); aTraceStr += " Bytes from "; aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding()); DBG_TRACE( aTraceStr.GetBuffer() ); #endif int nRead = 0; if ( IsOpen() ) { nRead = read(pInstanceData->nHandle,pData,(unsigned)nSize); if ( nRead == -1 ) SetError( ::GetSvError( errno )); } return (sal_Size)nRead; } /************************************************************************* |* |* SvFileStream::PutData() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ sal_Size SvFileStream::PutData( const void* pData, sal_Size nSize ) { #ifdef DBG_UTIL ByteString aTraceStr( "SvFileStrean::PutData: " ); aTraceStr += ByteString::CreateFromInt64(nSize); aTraceStr += " Bytes to "; aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding()); DBG_TRACE( aTraceStr.GetBuffer() ); #endif int nWrite = 0; if ( IsOpen() ) { nWrite = write(pInstanceData->nHandle,pData,(unsigned)nSize); if ( nWrite == -1 ) SetError( ::GetSvError( errno ) ); else if( !nWrite ) SetError( SVSTREAM_DISK_FULL ); } return (sal_Size)nWrite; } /************************************************************************* |* |* SvFileStream::SeekPos() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ sal_Size SvFileStream::SeekPos( sal_Size nPos ) { if ( IsOpen() ) { long nNewPos; if ( nPos != STREAM_SEEK_TO_END ) nNewPos = lseek( pInstanceData->nHandle, (long)nPos, SEEK_SET ); else nNewPos = lseek( pInstanceData->nHandle, 0L, SEEK_END ); if ( nNewPos == -1 ) { SetError( SVSTREAM_SEEK_ERROR ); return 0L; } // langsam aber sicherer als return nNewPos return lseek(pInstanceData->nHandle,0L,SEEK_CUR); // return nNewPos; } SetError( SVSTREAM_GENERALERROR ); return 0L; } /************************************************************************* |* |* SvFileStream::FlushData() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ void SvFileStream::FlushData() { // lokal gibt es nicht } static char *pFileLockEnvVar = (char*)1; /************************************************************************* |* |* SvFileStream::LockRange() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ sal_Bool SvFileStream::LockRange( sal_Size nByteOffset, sal_Size nBytes ) { struct flock aflock; aflock.l_start = nByteOffset; aflock.l_whence = SEEK_SET; aflock.l_len = nBytes; int nLockMode = 0; if ( ! IsOpen() ) return sal_False; if ( eStreamMode & STREAM_SHARE_DENYALL ) { if (bIsWritable) nLockMode = F_WRLCK; else nLockMode = F_RDLCK; } if ( eStreamMode & STREAM_SHARE_DENYREAD ) { if (bIsWritable) nLockMode = F_WRLCK; else { SetError(SVSTREAM_LOCKING_VIOLATION); return sal_False; } } if ( eStreamMode & STREAM_SHARE_DENYWRITE ) { if (bIsWritable) nLockMode = F_WRLCK; else nLockMode = F_RDLCK; } if (!nLockMode) return sal_True; if( ! InternalStreamLock::LockFile( nByteOffset, nByteOffset+nBytes, this ) ) { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "InternalLock on %s [ %d ... %d ] failed\n", ByteString(aFilename, osl_getThreadTextEncoding()).GetBuffer(), nByteOffset, nByteOffset+nBytes ); #endif return sal_False; } // HACK: File-Locking nur via Environmentvariable einschalten // um einen Haenger im Zusammenspiel mit einem Linux // NFS-2-Server (kein Lockdaemon) zu verhindern. // File-Locking ?ber NFS ist generell ein Performancekiller. // HR, 22.10.1997 fuer SOLARIS // CP, 30.11.1997 fuer HPUX // ER, 18.12.1997 fuer IRIX // HR, 18.05.1998 Environmentvariable if ( pFileLockEnvVar == (char*)1 ) pFileLockEnvVar = getenv("STAR_ENABLE_FILE_LOCKING"); if ( ! pFileLockEnvVar ) return sal_True; aflock.l_type = nLockMode; if (fcntl(pInstanceData->nHandle, F_GETLK, &aflock) == -1) { #if ( defined HPUX && defined BAD_UNION ) #ifdef DBG_UTIL fprintf( stderr, "***** FCNTL(lock):errno = %d\n", errno ); #endif if ( errno == EINVAL || errno == ENOSYS ) return sal_True; #endif #if defined SINIX if (errno == EINVAL) return sal_True; #endif #if defined SOLARIS if (errno == ENOSYS) return sal_True; #endif SetError( ::GetSvError( errno )); return sal_False; } if (aflock.l_type != F_UNLCK) { SetError(SVSTREAM_LOCKING_VIOLATION); return sal_False; } aflock.l_type = nLockMode; if (fcntl(pInstanceData->nHandle, F_SETLK, &aflock) == -1) { SetError( ::GetSvError( errno )); return sal_False; } return sal_True; } /************************************************************************* |* |* SvFileStream::UnlockRange() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ sal_Bool SvFileStream::UnlockRange( sal_Size nByteOffset, sal_Size nBytes ) { struct flock aflock; aflock.l_type = F_UNLCK; aflock.l_start = nByteOffset; aflock.l_whence = SEEK_SET; aflock.l_len = nBytes; if ( ! IsOpen() ) return sal_False; InternalStreamLock::UnlockFile( nByteOffset, nByteOffset+nBytes, this ); if ( ! (eStreamMode & (STREAM_SHARE_DENYALL | STREAM_SHARE_DENYREAD | STREAM_SHARE_DENYWRITE))) return sal_True; // wenn File Locking ausgeschaltet, siehe SvFileStream::LockRange if ( ! pFileLockEnvVar ) return sal_True; if (fcntl(pInstanceData->nHandle, F_SETLK, &aflock) != -1) return sal_True; #if ( defined HPUX && defined BAD_UNION ) #ifdef DBG_UTIL fprintf( stderr, "***** FCNTL(unlock):errno = %d\n", errno ); #endif if ( errno == EINVAL || errno == ENOSYS ) return sal_True; #endif #if ( defined SINIX ) if (errno == EINVAL) return sal_True; #endif SetError( ::GetSvError( errno )); return sal_False; } /************************************************************************* |* |* SvFileStream::LockFile() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ sal_Bool SvFileStream::LockFile() { return LockRange( 0UL, 0UL ); } /************************************************************************* |* |* SvFileStream::UnlockFile() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ sal_Bool SvFileStream::UnlockFile() { return UnlockRange( 0UL, 0UL ); } /************************************************************************* |* |* SvFileStream::Open() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ void SvFileStream::Open( const String& rFilename, StreamMode nOpenMode ) { int nAccess, nAccessRW; int nMode; int nHandleTmp; struct stat buf; sal_Bool bStatValid = sal_False; Close(); errno = 0; eStreamMode = nOpenMode; eStreamMode &= ~STREAM_TRUNC; // beim ReOpen nicht cutten // !!! NoOp: Ansonsten ToAbs() verwendern // !!! DirEntry aDirEntry( rFilename ); // !!! aFilename = aDirEntry.GetFull(); aFilename = rFilename; #ifndef BOOTSTRAP FSysRedirector::DoRedirect( aFilename ); #endif ByteString aLocalFilename(aFilename, osl_getThreadTextEncoding()); #ifdef DBG_UTIL ByteString aTraceStr( "SvFileStream::Open(): " ); aTraceStr += aLocalFilename; DBG_TRACE( aTraceStr.GetBuffer() ); #endif if ( lstat( aLocalFilename.GetBuffer(), &buf ) == 0 ) { bStatValid = sal_True; // SvFileStream soll kein Directory oeffnen if( S_ISDIR( buf.st_mode ) ) { SetError( ::GetSvError( EISDIR ) ); return; } } if ( !( nOpenMode & STREAM_WRITE ) ) nAccessRW = O_RDONLY; else if ( !( nOpenMode & STREAM_READ ) ) nAccessRW = O_WRONLY; else nAccessRW = O_RDWR; nAccess = 0; // Fix (MDA, 18.01.95): Bei RD_ONLY nicht mit O_CREAT oeffnen // Wichtig auf Read-Only-Dateisystemen (wie CDROM) if ( (!( nOpenMode & STREAM_NOCREATE )) && ( nAccessRW != O_RDONLY ) ) nAccess |= O_CREAT; if ( nOpenMode & STREAM_TRUNC ) nAccess |= O_TRUNC; nMode = S_IREAD | S_IROTH | S_IRGRP; if ( nOpenMode & STREAM_WRITE) { nMode |= (S_IWRITE | S_IWOTH | S_IWGRP); if ( nOpenMode & STREAM_COPY_ON_SYMLINK ) { if ( bStatValid && S_ISLNK( buf.st_mode ) < 0 ) { char *pBuf = new char[ 1024+1 ]; if ( readlink( aLocalFilename.GetBuffer(), pBuf, 1024 ) > 0 ) { if ( unlink(aLocalFilename.GetBuffer()) == 0 ) { #ifdef DBG_UTIL fprintf( stderr, "Copying file on symbolic link (%s).\n", aLocalFilename.GetBuffer() ); #endif String aTmpString( pBuf, osl_getThreadTextEncoding() ); const DirEntry aSourceEntry( aTmpString ); const DirEntry aTargetEntry( aFilename ); FileCopier aFileCopier( aSourceEntry, aTargetEntry ); aFileCopier.Execute(); } } delete pBuf; } } } nHandleTmp = open(aLocalFilename.GetBuffer(),nAccessRW|nAccess, nMode ); if ( nHandleTmp == -1 ) { if ( nAccessRW != O_RDONLY ) { // auf Lesen runterschalten nAccessRW = O_RDONLY; nAccess = 0; nMode = S_IREAD | S_IROTH | S_IRGRP; nHandleTmp =open( aLocalFilename.GetBuffer(), nAccessRW|nAccess, nMode ); } } if ( nHandleTmp != -1 ) { pInstanceData->nHandle = nHandleTmp; bIsOpen = sal_True; if ( nAccessRW != O_RDONLY ) bIsWritable = sal_True; if ( !LockFile() ) // ganze Datei { close( nHandleTmp ); bIsOpen = sal_False; bIsWritable = sal_False; pInstanceData->nHandle = 0; } } else SetError( ::GetSvError( errno ) ); } /************************************************************************* |* |* SvFileStream::ReOpen() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ void SvFileStream::ReOpen() { if ( !bIsOpen && aFilename.Len() ) Open( aFilename, eStreamMode ); } /************************************************************************* |* |* SvFileStream::Close() |* |* Beschreibung STREAM.SDW |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ void SvFileStream::Close() { InternalStreamLock::UnlockFile( 0, 0, this ); if ( IsOpen() ) { #ifdef DBG_UTIL ByteString aTraceStr( "SvFileStream::Close(): " ); aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding()); DBG_TRACE( aTraceStr.GetBuffer() ); #endif Flush(); close( pInstanceData->nHandle ); pInstanceData->nHandle = 0; } bIsOpen = sal_False; bIsWritable = sal_False; SvStream::ClearBuffer(); SvStream::ClearError(); } /************************************************************************* |* |* SvFileStream::ResetError() |* |* Beschreibung STREAM.SDW; Setzt Filepointer auf Dateianfang |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ void SvFileStream::ResetError() { SvStream::ClearError(); } /************************************************************************* |* |* SvFileStream::SetSize() |* |* Beschreibung STREAM.SDW; |* Ersterstellung OV 15.06.94 |* Letzte Aenderung OV 15.06.94 |* *************************************************************************/ void SvFileStream::SetSize (sal_Size nSize) { if (IsOpen()) { int fd = pInstanceData->nHandle; if (::ftruncate (fd, (off_t)nSize) < 0) { // Save original error. sal_uInt32 nErr = ::GetSvError (errno); // Check against current size. Fail upon 'shrink'. struct stat aStat; if (::fstat (fd, &aStat) < 0) { SetError (nErr); return; } if ((sal::static_int_cast< sal_sSize >(nSize) <= aStat.st_size)) { // Failure upon 'shrink'. Return original error. SetError (nErr); return; } // Save current position. sal_Size nCurPos = (sal_Size)::lseek (fd, (off_t)0, SEEK_CUR); if (nCurPos == (sal_Size)(-1)) { SetError (nErr); return; } // Try 'expand' via 'lseek()' and 'write()'. if (::lseek (fd, (off_t)(nSize - 1), SEEK_SET) < 0) { SetError (nErr); return; } if (::write (fd, (char*)"", (size_t)1) < 0) { // Failure. Restore saved position. if (::lseek (fd, (off_t)nCurPos, SEEK_SET) < 0) { // Double failure. } SetError (nErr); return; } // Success. Restore saved position. if (::lseek (fd, (off_t)nCurPos, SEEK_SET) < 0) { SetError (nErr); return; } } } }