fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / tools / source / stream / strmunx.cxx
blobc8e5986daa6ac21a0861318e822873c496de4fc6
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/stream.hxx>
29 #include <vector>
31 #include <osl/mutex.hxx>
32 #include <osl/thread.h>
33 #include <sal/log.hxx>
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 {
47 struct LockMutex : public rtl::Static< osl::Mutex, LockMutex > {};
49 struct InternalStreamLock
51 sal_Size m_nStartPos;
52 sal_Size m_nEndPos;
53 SvFileStream* m_pStream;
54 osl::DirectoryItem m_aItem;
56 InternalStreamLock( sal_Size, sal_Size, SvFileStream* );
57 ~InternalStreamLock();
60 struct LockList : public rtl::Static< std::vector<InternalStreamLock>, LockList > {};
62 InternalStreamLock::InternalStreamLock(
63 sal_Size nStart,
64 sal_Size nEnd,
65 SvFileStream* pStream ) :
66 m_nStartPos( nStart ),
67 m_nEndPos( nEnd ),
68 m_pStream( pStream )
70 osl::DirectoryItem::get( m_pStream->GetFileName(), m_aItem );
71 #if OSL_DEBUG_LEVEL > 1
72 OString aFileName(OUStringToOString(m_pStream->GetFileName(),
73 osl_getThreadTextEncoding()));
74 fprintf( stderr, "locked %s", aFileName.getStr() );
75 if( m_nStartPos || m_nEndPos )
76 fprintf(stderr, " [ %ld ... %ld ]", m_nStartPos, m_nEndPos );
77 fprintf( stderr, "\n" );
78 #endif
81 InternalStreamLock::~InternalStreamLock()
83 #if OSL_DEBUG_LEVEL > 1
84 OString aFileName(OUStringToOString(m_pStream->GetFileName(),
85 osl_getThreadTextEncoding()));
86 fprintf( stderr, "unlocked %s", aFileName.getStr() );
87 if( m_nStartPos || m_nEndPos )
88 fprintf(stderr, " [ %ld ... %ld ]", m_nStartPos, m_nEndPos );
89 fprintf( stderr, "\n" );
90 #endif
93 bool lockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream )
95 osl::DirectoryItem aItem;
96 if (osl::DirectoryItem::get( pStream->GetFileName(), aItem) != osl::FileBase::E_None )
98 SAL_INFO("tools.stream", "Failed to lookup stream for locking");
99 return true;
102 osl::FileStatus aStatus( osl_FileStatus_Mask_Type );
103 if ( aItem.getFileStatus( aStatus ) != osl::FileBase::E_None )
105 SAL_INFO("tools.stream", "Failed to stat stream for locking");
106 return true;
108 if( aStatus.getFileType() == osl::FileStatus::Directory )
109 return true;
111 osl::MutexGuard aGuard( LockMutex::get() );
112 std::vector<InternalStreamLock> &rLockList = LockList::get();
113 for( std::vector<InternalStreamLock>::const_iterator i = rLockList.begin();
114 i != rLockList.end(); )
116 if( aItem.isIdenticalTo( i->m_aItem ) )
118 bool bDenyByOptions = false;
119 StreamMode nLockMode = i->m_pStream->GetStreamMode();
120 StreamMode nNewMode = pStream->GetStreamMode();
122 if( nLockMode & StreamMode::SHARE_DENYALL )
123 bDenyByOptions = true;
124 else if( ( nLockMode & StreamMode::SHARE_DENYWRITE ) &&
125 ( nNewMode & StreamMode::WRITE ) )
126 bDenyByOptions = true;
127 else if( ( nLockMode &StreamMode::SHARE_DENYREAD ) &&
128 ( nNewMode & StreamMode::READ ) )
129 bDenyByOptions = true;
131 if( bDenyByOptions )
133 if( i->m_nStartPos == 0 && i->m_nEndPos == 0 ) // whole file is already locked
134 return false;
135 if( nStart == 0 && nEnd == 0) // cannot lock whole file
136 return false;
138 if( ( nStart < i->m_nStartPos && nEnd > i->m_nStartPos ) ||
139 ( nStart < i->m_nEndPos && nEnd > i->m_nEndPos ) )
140 return false;
144 rLockList.push_back( InternalStreamLock( nStart, nEnd, pStream ) );
145 return true;
148 void unlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream )
150 osl::MutexGuard aGuard( LockMutex::get() );
151 std::vector<InternalStreamLock> &rLockList = LockList::get();
152 for( std::vector<InternalStreamLock>::iterator i = rLockList.begin();
153 i != rLockList.end(); )
155 if ( i->m_pStream == pStream
156 && ( ( nStart == 0 && nEnd == 0 )
157 || ( i->m_nStartPos == nStart && i->m_nEndPos == nEnd ) ) )
159 i = rLockList.erase(i);
161 else
163 ++i;
170 // StreamData ------------------------------------------------------------------
172 class StreamData
174 public:
175 oslFileHandle rHandle;
177 StreamData() : rHandle( 0 ) { }
180 static sal_uInt32 GetSvError( int nErrno )
182 static struct { int nErr; sal_uInt32 sv; } errArr[] =
184 { 0, SVSTREAM_OK },
185 { EACCES, SVSTREAM_ACCESS_DENIED },
186 { EBADF, SVSTREAM_INVALID_HANDLE },
187 #if defined(NETBSD) || \
188 defined(FREEBSD) || defined(MACOSX) || defined(OPENBSD) || \
189 defined(__FreeBSD_kernel__) || defined (AIX) || defined(DRAGONFLY) || \
190 defined(IOS)
191 { EDEADLK, SVSTREAM_LOCKING_VIOLATION },
192 #else
193 { EDEADLOCK, SVSTREAM_LOCKING_VIOLATION },
194 #endif
195 { EINVAL, SVSTREAM_INVALID_PARAMETER },
196 { EMFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
197 { ENFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
198 { ENOENT, SVSTREAM_FILE_NOT_FOUND },
199 { EPERM, SVSTREAM_ACCESS_DENIED },
200 { EROFS, SVSTREAM_ACCESS_DENIED },
201 { EAGAIN, SVSTREAM_LOCKING_VIOLATION },
202 { EISDIR, SVSTREAM_PATH_NOT_FOUND },
203 { ELOOP, SVSTREAM_PATH_NOT_FOUND },
204 #if !defined(NETBSD) && !defined (FREEBSD) && \
205 !defined(MACOSX) && !defined(OPENBSD) && !defined(__FreeBSD_kernel__) && \
206 !defined(DRAGONFLY)
207 { EMULTIHOP, SVSTREAM_PATH_NOT_FOUND },
208 { ENOLINK, SVSTREAM_PATH_NOT_FOUND },
209 #endif
210 { ENOTDIR, SVSTREAM_PATH_NOT_FOUND },
211 { ETXTBSY, SVSTREAM_ACCESS_DENIED },
212 { EEXIST, SVSTREAM_CANNOT_MAKE },
213 { ENOSPC, SVSTREAM_DISK_FULL },
214 { (int)0xFFFF, SVSTREAM_GENERALERROR }
217 sal_uInt32 nRetVal = SVSTREAM_GENERALERROR; // default error
218 int i=0;
221 if ( errArr[i].nErr == nErrno )
223 nRetVal = errArr[i].sv;
224 break;
226 ++i;
228 while( errArr[i].nErr != 0xFFFF );
229 return nRetVal;
232 static sal_uInt32 GetSvError( oslFileError nErrno )
234 static struct { oslFileError nErr; sal_uInt32 sv; } errArr[] =
236 { osl_File_E_None, SVSTREAM_OK },
237 { osl_File_E_ACCES, SVSTREAM_ACCESS_DENIED },
238 { osl_File_E_BADF, SVSTREAM_INVALID_HANDLE },
239 { osl_File_E_DEADLK, SVSTREAM_LOCKING_VIOLATION },
240 { osl_File_E_INVAL, SVSTREAM_INVALID_PARAMETER },
241 { osl_File_E_MFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
242 { osl_File_E_NFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
243 { osl_File_E_NOENT, SVSTREAM_FILE_NOT_FOUND },
244 { osl_File_E_PERM, SVSTREAM_ACCESS_DENIED },
245 { osl_File_E_ROFS, SVSTREAM_ACCESS_DENIED },
246 { osl_File_E_AGAIN, SVSTREAM_LOCKING_VIOLATION },
247 { osl_File_E_ISDIR, SVSTREAM_PATH_NOT_FOUND },
248 { osl_File_E_LOOP, SVSTREAM_PATH_NOT_FOUND },
249 { osl_File_E_MULTIHOP, SVSTREAM_PATH_NOT_FOUND },
250 { osl_File_E_NOLINK, SVSTREAM_PATH_NOT_FOUND },
251 { osl_File_E_NOTDIR, SVSTREAM_PATH_NOT_FOUND },
252 { osl_File_E_EXIST, SVSTREAM_CANNOT_MAKE },
253 { osl_File_E_NOSPC, SVSTREAM_DISK_FULL },
254 { (oslFileError)0xFFFF, SVSTREAM_GENERALERROR }
257 sal_uInt32 nRetVal = SVSTREAM_GENERALERROR; // default error
258 int i=0;
261 if ( errArr[i].nErr == nErrno )
263 nRetVal = errArr[i].sv;
264 break;
266 ++i;
268 while( errArr[i].nErr != (oslFileError)0xFFFF );
269 return nRetVal;
272 SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nOpenMode )
274 bIsOpen = false;
275 nLockCounter = 0;
276 bIsWritable = false;
277 pInstanceData = new StreamData;
279 SetBufferSize( 1024 );
280 // convert URL to SystemPath, if necessary
281 OUString aSystemFileName;
282 if( FileBase::getSystemPathFromFileURL( rFileName , aSystemFileName )
283 != FileBase::E_None )
285 aSystemFileName = rFileName;
287 Open( aSystemFileName, nOpenMode );
290 SvFileStream::SvFileStream()
292 bIsOpen = false;
293 nLockCounter = 0;
294 bIsWritable = false;
295 pInstanceData = new StreamData;
296 SetBufferSize( 1024 );
299 SvFileStream::~SvFileStream()
301 Close();
303 unlockFile( 0, 0, this );
305 if (pInstanceData)
306 delete pInstanceData;
309 sal_Size SvFileStream::GetData( void* pData, sal_Size nSize )
311 #ifdef DBG_UTIL
312 OStringBuffer aTraceStr("SvFileStream::GetData(): ");
313 aTraceStr.append(static_cast<sal_Int64>(nSize));
314 aTraceStr.append(" Bytes from ");
315 aTraceStr.append(OUStringToOString(aFilename,
316 osl_getThreadTextEncoding()));
317 OSL_TRACE("%s", aTraceStr.getStr());
318 #endif
320 sal_uInt64 nRead = 0;
321 if ( IsOpen() )
323 oslFileError rc = osl_readFile(pInstanceData->rHandle,pData,(sal_uInt64)nSize,&nRead);
324 if ( rc != osl_File_E_None )
326 SetError( ::GetSvError( rc ));
327 return -1;
330 return (sal_Size)nRead;
333 sal_Size SvFileStream::PutData( const void* pData, sal_Size nSize )
335 #ifdef DBG_UTIL
336 OStringBuffer aTraceStr("SvFileStream::PutData(): ");
337 aTraceStr.append(static_cast<sal_Int64>(nSize));
338 aTraceStr.append(" Bytes to ");
339 aTraceStr.append(OUStringToOString(aFilename,
340 osl_getThreadTextEncoding()));
341 OSL_TRACE("%s", aTraceStr.getStr());
342 #endif
344 sal_uInt64 nWrite = 0;
345 if ( IsOpen() )
347 oslFileError rc = osl_writeFile(pInstanceData->rHandle,pData,(sal_uInt64)nSize,&nWrite);
348 if ( rc != osl_File_E_None )
350 SetError( ::GetSvError( rc ) );
351 return -1;
353 else if( !nWrite )
354 SetError( SVSTREAM_DISK_FULL );
356 return (sal_Size)nWrite;
359 sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos)
361 // check if a truncated STREAM_SEEK_TO_END was passed
362 assert(nPos != (sal_uInt64)(sal_uInt32)STREAM_SEEK_TO_END);
363 if ( IsOpen() )
365 oslFileError rc;
366 sal_uInt64 nNewPos;
367 if ( nPos != STREAM_SEEK_TO_END )
368 rc = osl_setFilePos( pInstanceData->rHandle, osl_Pos_Absolut, nPos );
369 else
370 rc = osl_setFilePos( pInstanceData->rHandle, osl_Pos_End, 0 );
372 if ( rc != osl_File_E_None )
374 SetError( SVSTREAM_SEEK_ERROR );
375 return 0L;
377 if ( nPos != STREAM_SEEK_TO_END )
378 return nPos;
379 rc = osl_getFilePos( pInstanceData->rHandle, &nNewPos );
380 return (sal_Size) nNewPos;
382 SetError( SVSTREAM_GENERALERROR );
383 return 0L;
386 void SvFileStream::FlushData()
388 // does not exist locally
391 bool SvFileStream::LockRange( sal_Size nByteOffset, sal_Size nBytes )
393 int nLockMode = 0;
395 if ( ! IsOpen() )
396 return false;
398 if ( eStreamMode & StreamMode::SHARE_DENYALL )
400 if (bIsWritable)
401 nLockMode = F_WRLCK;
402 else
403 nLockMode = F_RDLCK;
406 if ( eStreamMode & StreamMode::SHARE_DENYREAD )
408 if (bIsWritable)
409 nLockMode = F_WRLCK;
410 else
412 SetError(SVSTREAM_LOCKING_VIOLATION);
413 return false;
417 if ( eStreamMode & StreamMode::SHARE_DENYWRITE )
419 if (bIsWritable)
420 nLockMode = F_WRLCK;
421 else
422 nLockMode = F_RDLCK;
425 if (!nLockMode)
426 return true;
428 if( !lockFile( nByteOffset, nByteOffset+nBytes, this ) )
430 #if OSL_DEBUG_LEVEL > 1
431 fprintf( stderr, "InternalLock on %s [ %ld ... %ld ] failed\n",
432 OUStringToOString(aFilename, osl_getThreadTextEncoding()).getStr(), nByteOffset, nByteOffset+nBytes );
433 #endif
434 return false;
437 return true;
440 bool SvFileStream::UnlockRange( sal_Size nByteOffset, sal_Size nBytes )
442 if ( ! IsOpen() )
443 return false;
445 unlockFile( nByteOffset, nByteOffset+nBytes, this );
447 return true;
450 bool SvFileStream::LockFile()
452 return LockRange( 0UL, 0UL );
455 bool SvFileStream::UnlockFile()
457 return UnlockRange( 0UL, 0UL );
460 void SvFileStream::Open( const OUString& rFilename, StreamMode nOpenMode )
462 sal_uInt32 uFlags;
463 oslFileHandle nHandleTmp;
465 Close();
466 errno = 0;
467 eStreamMode = nOpenMode;
468 eStreamMode &= ~StreamMode::TRUNC; // don't truncat on reopen
470 aFilename = rFilename;
472 #ifdef DBG_UTIL
473 OString aLocalFilename(OUStringToOString(aFilename, osl_getThreadTextEncoding()));
474 OStringBuffer aTraceStr("SvFileStream::Open(): ");
475 aTraceStr.append(aLocalFilename);
476 OSL_TRACE( "%s", aTraceStr.getStr() );
477 #endif
479 OUString aFileURL;
480 osl::DirectoryItem aItem;
481 osl::FileStatus aStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_LinkTargetURL );
483 // FIXME: we really need to switch to a pure URL model ...
484 if ( osl::File::getFileURLFromSystemPath( aFilename, aFileURL ) != osl::FileBase::E_None )
485 aFileURL = aFilename;
486 bool bStatValid = ( osl::DirectoryItem::get( aFileURL, aItem) == osl::FileBase::E_None &&
487 aItem.getFileStatus( aStatus ) == osl::FileBase::E_None );
489 // SvFileStream can't open a directory
490 if( bStatValid && aStatus.getFileType() == osl::FileStatus::Directory )
492 SetError( ::GetSvError( EISDIR ) );
493 return;
496 if ( !( nOpenMode & StreamMode::WRITE ) )
497 uFlags = osl_File_OpenFlag_Read;
498 else if ( !( nOpenMode & StreamMode::READ ) )
499 uFlags = osl_File_OpenFlag_Write;
500 else
501 uFlags = osl_File_OpenFlag_Read | osl_File_OpenFlag_Write;
503 // Fix (MDA, 18.01.95): Don't open with O_CREAT upon RD_ONLY
504 // Important for Read-Only-Filesystems (e.g, CDROM)
505 if ( (!( nOpenMode & StreamMode::NOCREATE )) && ( uFlags != osl_File_OpenFlag_Read ) )
506 uFlags |= osl_File_OpenFlag_Create;
507 if ( nOpenMode & StreamMode::TRUNC )
508 uFlags |= osl_File_OpenFlag_Trunc;
510 uFlags |= osl_File_OpenFlag_NoExcl | osl_File_OpenFlag_NoLock;
512 if ( nOpenMode & StreamMode::WRITE)
514 if ( nOpenMode & StreamMode::COPY_ON_SYMLINK )
516 if ( bStatValid && aStatus.getFileType() == osl::FileStatus::Link &&
517 aStatus.getLinkTargetURL().getLength() > 0 )
519 // delete the symbolic link, and replace it with the contents of the link
520 if (osl::File::remove( aFileURL ) == osl::FileBase::E_None )
522 File::copy( aStatus.getLinkTargetURL(), aFileURL );
523 #if OSL_DEBUG_LEVEL > 0
524 fprintf( stderr,
525 "Removing link and replacing with file contents (%s) -> (%s).\n",
526 OUStringToOString( aStatus.getLinkTargetURL(),
527 RTL_TEXTENCODING_UTF8).getStr(),
528 OUStringToOString( aFileURL,
529 RTL_TEXTENCODING_UTF8).getStr() );
530 #endif
536 oslFileError rc = osl_openFile( aFileURL.pData, &nHandleTmp, uFlags );
537 if ( rc != osl_File_E_None )
539 if ( uFlags & osl_File_OpenFlag_Write )
541 // Change to read-only
542 uFlags &= ~osl_File_OpenFlag_Write;
543 rc = osl_openFile( aFileURL.pData, &nHandleTmp, uFlags );
546 if ( rc == osl_File_E_None )
548 pInstanceData->rHandle = nHandleTmp;
549 bIsOpen = true;
550 if ( uFlags & osl_File_OpenFlag_Write )
551 bIsWritable = true;
553 if ( !LockFile() ) // whole file
555 rc = osl_closeFile( nHandleTmp );
556 bIsOpen = false;
557 bIsWritable = false;
558 pInstanceData->rHandle = 0;
561 else
562 SetError( ::GetSvError( rc ) );
565 void SvFileStream::Close()
567 UnlockFile();
569 if ( IsOpen() )
571 #ifdef DBG_UTIL
572 OStringBuffer aTraceStr("SvFileStream::Close(): ");
573 aTraceStr.append(OUStringToOString(aFilename,
574 osl_getThreadTextEncoding()));
575 OSL_TRACE("%s", aTraceStr.getStr());
576 #endif
578 Flush();
579 osl_closeFile( pInstanceData->rHandle );
580 pInstanceData->rHandle = 0;
583 bIsOpen = false;
584 bIsWritable = false;
585 SvStream::ClearBuffer();
586 SvStream::ClearError();
589 /// set filepointer to beginning of file
590 void SvFileStream::ResetError()
592 SvStream::ClearError();
595 void SvFileStream::SetSize (sal_uInt64 const nSize)
597 if (IsOpen())
599 oslFileError rc = osl_setFileSize( pInstanceData->rHandle, nSize );
600 if (rc != osl_File_E_None )
602 SetError ( ::GetSvError( rc ));
607 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */