fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / tools / source / stream / strmunx.cxx
blob65b051a253f7a67e7ac5f971748bb99c8cd2cce8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <stdio.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <limits.h>
28 #include <tools/debug.hxx>
29 #include <tools/stream.hxx>
30 #include <vector>
32 #include <osl/mutex.hxx>
33 #include <osl/thread.h> // osl_getThreadTextEncoding
35 // class FileBase
36 #include <osl/file.hxx>
37 #include <osl/detail/file.h>
38 #include <rtl/instance.hxx>
39 #include <rtl/strbuf.hxx>
41 using namespace osl;
43 // InternalLock ----------------------------------------------------------------
45 namespace { struct LockMutex : public rtl::Static< osl::Mutex, LockMutex > {}; }
47 class InternalStreamLock
49 sal_Size m_nStartPos;
50 sal_Size m_nEndPos;
51 SvFileStream* m_pStream;
52 osl::DirectoryItem m_aItem;
54 InternalStreamLock( sal_Size, sal_Size, SvFileStream* );
55 ~InternalStreamLock();
56 public:
57 static sal_Bool LockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* );
58 static void UnlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* );
61 typedef ::std::vector< InternalStreamLock* > InternalStreamLockList;
63 namespace { struct LockList : public rtl::Static< InternalStreamLockList, LockList > {}; }
65 InternalStreamLock::InternalStreamLock(
66 sal_Size nStart,
67 sal_Size nEnd,
68 SvFileStream* pStream ) :
69 m_nStartPos( nStart ),
70 m_nEndPos( nEnd ),
71 m_pStream( pStream )
73 osl::DirectoryItem::get( m_pStream->GetFileName(), m_aItem );
74 LockList::get().push_back( this );
75 #if OSL_DEBUG_LEVEL > 1
76 OString aFileName(OUStringToOString(m_pStream->GetFileName(),
77 osl_getThreadTextEncoding()));
78 fprintf( stderr, "locked %s", aFileName.getStr() );
79 if( m_nStartPos || m_nEndPos )
80 fprintf(stderr, " [ %ld ... %ld ]", m_nStartPos, m_nEndPos );
81 fprintf( stderr, "\n" );
82 #endif
85 InternalStreamLock::~InternalStreamLock()
87 for ( InternalStreamLockList::iterator it = LockList::get().begin();
88 it != LockList::get().end();
89 ++it
90 ) {
91 if ( this == *it ) {
92 LockList::get().erase( it );
93 break;
96 #if OSL_DEBUG_LEVEL > 1
97 OString aFileName(OUStringToOString(m_pStream->GetFileName(),
98 osl_getThreadTextEncoding()));
99 fprintf( stderr, "unlocked %s", aFileName.getStr() );
100 if( m_nStartPos || m_nEndPos )
101 fprintf(stderr, " [ %ld ... %ld ]", m_nStartPos, m_nEndPos );
102 fprintf( stderr, "\n" );
103 #endif
106 sal_Bool InternalStreamLock::LockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream )
108 osl::MutexGuard aGuard( LockMutex::get() );
109 osl::DirectoryItem aItem;
110 if (osl::DirectoryItem::get( pStream->GetFileName(), aItem) != osl::FileBase::E_None )
112 SAL_INFO("tools.stream", "Failed to lookup stream for locking");
113 return sal_True;
116 osl::FileStatus aStatus( osl_FileStatus_Mask_Type );
117 if ( aItem.getFileStatus( aStatus ) != osl::FileBase::E_None )
119 SAL_INFO("tools.stream", "Failed to stat stream for locking");
120 return sal_True;
122 if( aStatus.getFileType() == osl::FileStatus::Directory )
123 return sal_True;
125 InternalStreamLock* pLock = NULL;
126 InternalStreamLockList &rLockList = LockList::get();
127 for( size_t i = 0; i < rLockList.size(); ++i )
129 pLock = rLockList[ i ];
130 if( aItem.isIdenticalTo( pLock->m_aItem ) )
132 sal_Bool bDenyByOptions = sal_False;
133 StreamMode nLockMode = pLock->m_pStream->GetStreamMode();
134 StreamMode nNewMode = pStream->GetStreamMode();
136 if( nLockMode & STREAM_SHARE_DENYALL )
137 bDenyByOptions = sal_True;
138 else if( ( nLockMode & STREAM_SHARE_DENYWRITE ) &&
139 ( nNewMode & STREAM_WRITE ) )
140 bDenyByOptions = sal_True;
141 else if( ( nLockMode & STREAM_SHARE_DENYREAD ) &&
142 ( nNewMode & STREAM_READ ) )
143 bDenyByOptions = sal_True;
145 if( bDenyByOptions )
147 if( pLock->m_nStartPos == 0 && pLock->m_nEndPos == 0 ) // whole file is already locked
148 return sal_False;
149 if( nStart == 0 && nEnd == 0) // cannot lock whole file
150 return sal_False;
152 if( ( nStart < pLock->m_nStartPos && nEnd > pLock->m_nStartPos ) ||
153 ( nStart < pLock->m_nEndPos && nEnd > pLock->m_nEndPos ) )
154 return sal_False;
158 // hint: new InternalStreamLock() adds the entry to the global list
159 pLock = new InternalStreamLock( nStart, nEnd, pStream );
160 return sal_True;
163 void InternalStreamLock::UnlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream )
165 osl::MutexGuard aGuard( LockMutex::get() );
166 InternalStreamLock* pLock = NULL;
167 InternalStreamLockList &rLockList = LockList::get();
168 if( nStart == 0 && nEnd == 0 )
170 // nStart & nEnd = 0, so delete all locks
171 for( size_t i = 0; i < rLockList.size(); ++i )
173 if( ( pLock = rLockList[ i ] )->m_pStream == pStream )
175 // hint: delete will remove pLock from the global list
176 delete pLock;
177 i--;
180 return;
182 for( size_t i = 0; i < rLockList.size(); ++i )
184 if ( ( pLock = rLockList[ i ] )->m_pStream == pStream
185 && nStart == pLock->m_nStartPos
186 && nEnd == pLock->m_nEndPos
188 // hint: delete will remove pLock from the global list
189 delete pLock;
190 return;
195 // StreamData ------------------------------------------------------------------
197 class StreamData
199 public:
200 oslFileHandle rHandle;
202 StreamData() : rHandle( 0 ) { }
205 static sal_uInt32 GetSvError( int nErrno )
207 static struct { int nErr; sal_uInt32 sv; } errArr[] =
209 { 0, SVSTREAM_OK },
210 { EACCES, SVSTREAM_ACCESS_DENIED },
211 { EBADF, SVSTREAM_INVALID_HANDLE },
212 #if defined(RS6000) || defined(NETBSD) || \
213 defined(FREEBSD) || defined(MACOSX) || defined(OPENBSD) || \
214 defined(__FreeBSD_kernel__) || defined (AIX) || defined(DRAGONFLY) || \
215 defined(IOS)
216 { EDEADLK, SVSTREAM_LOCKING_VIOLATION },
217 #else
218 { EDEADLOCK, SVSTREAM_LOCKING_VIOLATION },
219 #endif
220 { EINVAL, SVSTREAM_INVALID_PARAMETER },
221 { EMFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
222 { ENFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
223 { ENOENT, SVSTREAM_FILE_NOT_FOUND },
224 { EPERM, SVSTREAM_ACCESS_DENIED },
225 { EROFS, SVSTREAM_ACCESS_DENIED },
226 { EAGAIN, SVSTREAM_LOCKING_VIOLATION },
227 { EISDIR, SVSTREAM_PATH_NOT_FOUND },
228 { ELOOP, SVSTREAM_PATH_NOT_FOUND },
229 #if !defined(RS6000) && !defined(NETBSD) && !defined (FREEBSD) && \
230 !defined(MACOSX) && !defined(OPENBSD) && !defined(__FreeBSD_kernel__) && \
231 !defined(DRAGONFLY)
232 { EMULTIHOP, SVSTREAM_PATH_NOT_FOUND },
233 { ENOLINK, SVSTREAM_PATH_NOT_FOUND },
234 #endif
235 { ENOTDIR, SVSTREAM_PATH_NOT_FOUND },
236 { ETXTBSY, SVSTREAM_ACCESS_DENIED },
237 { EEXIST, SVSTREAM_CANNOT_MAKE },
238 { ENOSPC, SVSTREAM_DISK_FULL },
239 { (int)0xFFFF, SVSTREAM_GENERALERROR }
242 sal_uInt32 nRetVal = SVSTREAM_GENERALERROR; // default error
243 int i=0;
246 if ( errArr[i].nErr == nErrno )
248 nRetVal = errArr[i].sv;
249 break;
251 ++i;
253 while( errArr[i].nErr != 0xFFFF );
254 return nRetVal;
257 static sal_uInt32 GetSvError( oslFileError nErrno )
259 static struct { oslFileError nErr; sal_uInt32 sv; } errArr[] =
261 { osl_File_E_None, SVSTREAM_OK },
262 { osl_File_E_ACCES, SVSTREAM_ACCESS_DENIED },
263 { osl_File_E_BADF, SVSTREAM_INVALID_HANDLE },
264 { osl_File_E_DEADLK, SVSTREAM_LOCKING_VIOLATION },
265 { osl_File_E_INVAL, SVSTREAM_INVALID_PARAMETER },
266 { osl_File_E_MFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
267 { osl_File_E_NFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
268 { osl_File_E_NOENT, SVSTREAM_FILE_NOT_FOUND },
269 { osl_File_E_PERM, SVSTREAM_ACCESS_DENIED },
270 { osl_File_E_ROFS, SVSTREAM_ACCESS_DENIED },
271 { osl_File_E_AGAIN, SVSTREAM_LOCKING_VIOLATION },
272 { osl_File_E_ISDIR, SVSTREAM_PATH_NOT_FOUND },
273 { osl_File_E_LOOP, SVSTREAM_PATH_NOT_FOUND },
274 { osl_File_E_MULTIHOP, SVSTREAM_PATH_NOT_FOUND },
275 { osl_File_E_NOLINK, SVSTREAM_PATH_NOT_FOUND },
276 { osl_File_E_NOTDIR, SVSTREAM_PATH_NOT_FOUND },
277 { osl_File_E_EXIST, SVSTREAM_CANNOT_MAKE },
278 { osl_File_E_NOSPC, SVSTREAM_DISK_FULL },
279 { (oslFileError)0xFFFF, SVSTREAM_GENERALERROR }
282 sal_uInt32 nRetVal = SVSTREAM_GENERALERROR; // default error
283 int i=0;
286 if ( errArr[i].nErr == nErrno )
288 nRetVal = errArr[i].sv;
289 break;
291 ++i;
293 while( errArr[i].nErr != (oslFileError)0xFFFF );
294 return nRetVal;
297 SvFileStream::SvFileStream( const String& rFileName, StreamMode nOpenMode )
299 bIsOpen = sal_False;
300 nLockCounter = 0;
301 bIsWritable = sal_False;
302 pInstanceData = new StreamData;
304 SetBufferSize( 1024 );
305 // convert URL to SystemPath, if necessary
306 OUString aSystemFileName;
307 if( FileBase::getSystemPathFromFileURL( rFileName , aSystemFileName )
308 != FileBase::E_None )
310 aSystemFileName = rFileName;
312 Open( aSystemFileName, nOpenMode );
315 SvFileStream::SvFileStream()
317 bIsOpen = sal_False;
318 nLockCounter = 0;
319 bIsWritable = sal_False;
320 pInstanceData = new StreamData;
321 SetBufferSize( 1024 );
324 SvFileStream::~SvFileStream()
326 Close();
328 InternalStreamLock::UnlockFile( 0, 0, this );
330 if (pInstanceData)
331 delete pInstanceData;
334 sal_uInt32 SvFileStream::GetFileHandle() const
336 sal_IntPtr handle;
337 if (osl_getFileOSHandle(pInstanceData->rHandle, &handle) == osl_File_E_None)
338 return (sal_uInt32) handle;
339 else
340 return (sal_uInt32) -1;
343 sal_uInt16 SvFileStream::IsA() const
345 return ID_FILESTREAM;
348 sal_Size SvFileStream::GetData( void* pData, sal_Size nSize )
350 #ifdef DBG_UTIL
351 OStringBuffer aTraceStr("SvFileStream::GetData(): ");
352 aTraceStr.append(static_cast<sal_Int64>(nSize));
353 aTraceStr.append(" Bytes from ");
354 aTraceStr.append(OUStringToOString(aFilename,
355 osl_getThreadTextEncoding()));
356 OSL_TRACE("%s", aTraceStr.getStr());
357 #endif
359 sal_uInt64 nRead = 0;
360 if ( IsOpen() )
362 oslFileError rc = osl_readFile(pInstanceData->rHandle,pData,(sal_uInt64)nSize,&nRead);
363 if ( rc != osl_File_E_None )
365 SetError( ::GetSvError( rc ));
366 return -1;
369 return (sal_Size)nRead;
372 sal_Size SvFileStream::PutData( const void* pData, sal_Size nSize )
374 #ifdef DBG_UTIL
375 OStringBuffer aTraceStr("SvFileStream::PutData(): ");
376 aTraceStr.append(static_cast<sal_Int64>(nSize));
377 aTraceStr.append(" Bytes to ");
378 aTraceStr.append(OUStringToOString(aFilename,
379 osl_getThreadTextEncoding()));
380 OSL_TRACE("%s", aTraceStr.getStr());
381 #endif
383 sal_uInt64 nWrite = 0;
384 if ( IsOpen() )
386 oslFileError rc = osl_writeFile(pInstanceData->rHandle,pData,(sal_uInt64)nSize,&nWrite);
387 if ( rc != osl_File_E_None )
389 SetError( ::GetSvError( rc ) );
390 return -1;
392 else if( !nWrite )
393 SetError( SVSTREAM_DISK_FULL );
395 return (sal_Size)nWrite;
398 sal_Size SvFileStream::SeekPos( sal_Size nPos )
400 if ( IsOpen() )
402 oslFileError rc;
403 sal_uInt64 nNewPos;
404 if ( nPos != STREAM_SEEK_TO_END )
405 rc = osl_setFilePos( pInstanceData->rHandle, osl_Pos_Absolut, nPos );
406 else
407 rc = osl_setFilePos( pInstanceData->rHandle, osl_Pos_End, 0 );
409 if ( rc != osl_File_E_None )
411 SetError( SVSTREAM_SEEK_ERROR );
412 return 0L;
414 rc = osl_getFilePos( pInstanceData->rHandle, &nNewPos );
415 return (sal_Size) nNewPos;
417 SetError( SVSTREAM_GENERALERROR );
418 return 0L;
421 void SvFileStream::FlushData()
423 // does not exist locally
426 sal_Bool SvFileStream::LockRange( sal_Size nByteOffset, sal_Size nBytes )
428 int nLockMode = 0;
430 if ( ! IsOpen() )
431 return sal_False;
433 if ( eStreamMode & STREAM_SHARE_DENYALL )
435 if (bIsWritable)
436 nLockMode = F_WRLCK;
437 else
438 nLockMode = F_RDLCK;
441 if ( eStreamMode & STREAM_SHARE_DENYREAD )
443 if (bIsWritable)
444 nLockMode = F_WRLCK;
445 else
447 SetError(SVSTREAM_LOCKING_VIOLATION);
448 return sal_False;
452 if ( eStreamMode & STREAM_SHARE_DENYWRITE )
454 if (bIsWritable)
455 nLockMode = F_WRLCK;
456 else
457 nLockMode = F_RDLCK;
460 if (!nLockMode)
461 return sal_True;
463 if( ! InternalStreamLock::LockFile( nByteOffset, nByteOffset+nBytes, this ) )
465 #if OSL_DEBUG_LEVEL > 1
466 fprintf( stderr, "InternalLock on %s [ %ld ... %ld ] failed\n",
467 OUStringToOString(aFilename, osl_getThreadTextEncoding()).getStr(), nByteOffset, nByteOffset+nBytes );
468 #endif
469 return sal_False;
472 return sal_True;
475 sal_Bool SvFileStream::UnlockRange( sal_Size nByteOffset, sal_Size nBytes )
477 if ( ! IsOpen() )
478 return sal_False;
480 InternalStreamLock::UnlockFile( nByteOffset, nByteOffset+nBytes, this );
482 return sal_True;
485 sal_Bool SvFileStream::LockFile()
487 return LockRange( 0UL, 0UL );
490 sal_Bool SvFileStream::UnlockFile()
492 return UnlockRange( 0UL, 0UL );
495 void SvFileStream::Open( const String& rFilename, StreamMode nOpenMode )
497 sal_uInt32 uFlags;
498 oslFileHandle nHandleTmp;
500 Close();
501 errno = 0;
502 eStreamMode = nOpenMode;
503 eStreamMode &= ~STREAM_TRUNC; // don't truncat on reopen
505 aFilename = rFilename;
506 OString aLocalFilename(OUStringToOString(aFilename, osl_getThreadTextEncoding()));
508 #ifdef DBG_UTIL
509 OStringBuffer aTraceStr("SvFileStream::Open(): ");
510 aTraceStr.append(aLocalFilename);
511 OSL_TRACE( "%s", aTraceStr.getStr() );
512 #endif
514 OUString aFileURL;
515 osl::DirectoryItem aItem;
516 osl::FileStatus aStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_LinkTargetURL );
518 // FIXME: we really need to switch to a pure URL model ...
519 if ( osl::File::getFileURLFromSystemPath( aFilename, aFileURL ) != osl::FileBase::E_None )
520 aFileURL = aFilename;
521 bool bStatValid = ( osl::DirectoryItem::get( aFileURL, aItem) == osl::FileBase::E_None &&
522 aItem.getFileStatus( aStatus ) == osl::FileBase::E_None );
524 // SvFileStream can't open a directory
525 if( bStatValid && aStatus.getFileType() == osl::FileStatus::Directory )
527 SetError( ::GetSvError( EISDIR ) );
528 return;
531 if ( !( nOpenMode & STREAM_WRITE ) )
532 uFlags = osl_File_OpenFlag_Read;
533 else if ( !( nOpenMode & STREAM_READ ) )
534 uFlags = osl_File_OpenFlag_Write;
535 else
536 uFlags = osl_File_OpenFlag_Read | osl_File_OpenFlag_Write;
538 // Fix (MDA, 18.01.95): Don't open with O_CREAT upon RD_ONLY
539 // Important for Read-Only-Filesystems (e.g, CDROM)
540 if ( (!( nOpenMode & STREAM_NOCREATE )) && ( uFlags != osl_File_OpenFlag_Read ) )
541 uFlags |= osl_File_OpenFlag_Create;
542 if ( nOpenMode & STREAM_TRUNC )
543 uFlags |= osl_File_OpenFlag_Trunc;
545 uFlags |= osl_File_OpenFlag_NoExcl | osl_File_OpenFlag_NoLock;
547 if ( nOpenMode & STREAM_WRITE)
549 if ( nOpenMode & STREAM_COPY_ON_SYMLINK )
551 if ( bStatValid && aStatus.getFileType() == osl::FileStatus::Link &&
552 aStatus.getLinkTargetURL().getLength() > 0 )
554 // delete the symbolic link, and replace it with the contents of the link
555 if (osl::File::remove( aFileURL ) == osl::FileBase::E_None )
557 File::copy( aStatus.getLinkTargetURL(), aFileURL );
558 #if OSL_DEBUG_LEVEL > 0
559 fprintf( stderr,
560 "Removing link and replacing with file contents (%s) -> (%s).\n",
561 OUStringToOString( aStatus.getLinkTargetURL(),
562 RTL_TEXTENCODING_UTF8).getStr(),
563 OUStringToOString( aFileURL,
564 RTL_TEXTENCODING_UTF8).getStr() );
565 #endif
571 oslFileError rc = osl_openFile( aFileURL.pData, &nHandleTmp, uFlags );
572 if ( rc != osl_File_E_None )
574 if ( uFlags & osl_File_OpenFlag_Write )
576 // Change to read-only
577 uFlags &= ~osl_File_OpenFlag_Write;
578 rc = osl_openFile( aFileURL.pData, &nHandleTmp, uFlags );
581 if ( rc == osl_File_E_None )
583 pInstanceData->rHandle = nHandleTmp;
584 bIsOpen = sal_True;
585 if ( uFlags & osl_File_OpenFlag_Write )
586 bIsWritable = sal_True;
588 if ( !LockFile() ) // whole file
590 rc = osl_closeFile( nHandleTmp );
591 bIsOpen = sal_False;
592 bIsWritable = sal_False;
593 pInstanceData->rHandle = 0;
596 else
597 SetError( ::GetSvError( rc ) );
600 void SvFileStream::Close()
602 UnlockFile();
604 if ( IsOpen() )
606 #ifdef DBG_UTIL
607 OStringBuffer aTraceStr("SvFileStream::Close(): ");
608 aTraceStr.append(OUStringToOString(aFilename,
609 osl_getThreadTextEncoding()));
610 OSL_TRACE("%s", aTraceStr.getStr());
611 #endif
613 Flush();
614 osl_closeFile( pInstanceData->rHandle );
615 pInstanceData->rHandle = 0;
618 bIsOpen = sal_False;
619 bIsWritable = sal_False;
620 SvStream::ClearBuffer();
621 SvStream::ClearError();
624 /// set filepointer to beginning of file
625 void SvFileStream::ResetError()
627 SvStream::ClearError();
630 void SvFileStream::SetSize (sal_Size nSize)
632 if (IsOpen())
634 oslFileError rc = osl_setFileSize( pInstanceData->rHandle, nSize );
635 if (rc != osl_File_E_None )
637 SetError ( ::GetSvError( rc ));
642 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */