xref: /trunk/main/tools/source/stream/strmunx.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // no include "precompiled_tools.hxx" because this file is included in strmsys.cxx
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <limits.h>
37 #include <stdlib.h> // fuer getenv()
38 
39 #include <tools/debug.hxx>
40 #include <tools/fsys.hxx>
41 #include <tools/stream.hxx>
42 
43 #include <vos/mutex.hxx>
44 #include <osl/thread.h> // osl_getThreadTextEncoding
45 
46 // class FileBase
47 #include <osl/file.hxx>
48 #include <rtl/instance.hxx>
49 
50 using namespace osl;
51 
52 // -----------------------------------------------------------------------
53 
54 // ----------------
55 // - InternalLock -
56 // ----------------
57 
58 class InternalStreamLock;
59 DECLARE_LIST( InternalStreamLockList, InternalStreamLock* )
60 namespace { struct LockList : public rtl::Static< InternalStreamLockList, LockList > {}; }
61 
62 #ifndef BOOTSTRAP
63 namespace { struct LockMutex : public rtl::Static< vos::OMutex, LockMutex > {}; }
64 #endif
65 
66 class InternalStreamLock
67 {
68     sal_Size            m_nStartPos;
69     sal_Size            m_nEndPos;
70     SvFileStream*   m_pStream;
71     struct stat     m_aStat;
72 
73     InternalStreamLock( sal_Size, sal_Size, SvFileStream* );
74     ~InternalStreamLock();
75 public:
76     static sal_Bool LockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* );
77     static void UnlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* );
78 };
79 
80 InternalStreamLock::InternalStreamLock(
81     sal_Size nStart,
82     sal_Size nEnd,
83     SvFileStream* pStream ) :
84         m_nStartPos( nStart ),
85         m_nEndPos( nEnd ),
86         m_pStream( pStream )
87 {
88     ByteString aFileName(m_pStream->GetFileName(), osl_getThreadTextEncoding());
89     stat( aFileName.GetBuffer(), &m_aStat );
90     LockList::get().Insert( this, LIST_APPEND );
91 #if OSL_DEBUG_LEVEL > 1
92     fprintf( stderr, "locked %s", aFileName.GetBuffer() );
93     if( m_nStartPos || m_nEndPos )
94         fprintf(stderr, " [ %ld ... %ld ]", m_nStartPos, m_nEndPos );
95     fprintf( stderr, "\n" );
96 #endif
97 }
98 
99 InternalStreamLock::~InternalStreamLock()
100 {
101     LockList::get().Remove( this );
102 #if OSL_DEBUG_LEVEL > 1
103     ByteString aFileName(m_pStream->GetFileName(), osl_getThreadTextEncoding());
104     fprintf( stderr, "unlocked %s", aFileName.GetBuffer() );
105     if( m_nStartPos || m_nEndPos )
106         fprintf(stderr, " [ %ld ... %ld ]", m_nStartPos, m_nEndPos );
107     fprintf( stderr, "\n" );
108 #endif
109 }
110 
111 sal_Bool InternalStreamLock::LockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream )
112 {
113 #ifndef BOOTSTRAP
114     vos:: OGuard  aGuard( LockMutex::get() );
115 #endif
116     ByteString aFileName(pStream->GetFileName(), osl_getThreadTextEncoding());
117     struct stat aStat;
118     if( stat( aFileName.GetBuffer(), &aStat ) )
119         return sal_False;
120 
121     if( S_ISDIR( aStat.st_mode ) )
122         return sal_True;
123 
124     InternalStreamLock* pLock = NULL;
125     InternalStreamLockList &rLockList = LockList::get();
126     for( sal_uIntPtr i = 0; i < rLockList.Count(); ++i )
127     {
128         pLock = rLockList.GetObject( i );
129         if( aStat.st_ino == pLock->m_aStat.st_ino )
130         {
131             sal_Bool bDenyByOptions = sal_False;
132             StreamMode nLockMode = pLock->m_pStream->GetStreamMode();
133             StreamMode nNewMode = pStream->GetStreamMode();
134 
135             if( nLockMode & STREAM_SHARE_DENYALL )
136                 bDenyByOptions = sal_True;
137             else if( ( nLockMode & STREAM_SHARE_DENYWRITE ) &&
138                      ( nNewMode & STREAM_WRITE ) )
139                 bDenyByOptions = sal_True;
140             else if( ( nLockMode & STREAM_SHARE_DENYREAD ) &&
141                      ( nNewMode & STREAM_READ ) )
142                 bDenyByOptions = sal_True;
143 
144             if( bDenyByOptions )
145             {
146                 if( pLock->m_nStartPos == 0 && pLock->m_nEndPos == 0 ) // whole file is already locked
147                     return sal_False;
148                 if( nStart == 0 && nEnd == 0) // cannot lock whole file
149                     return sal_False;
150 
151                 if( ( nStart < pLock->m_nStartPos && nEnd > pLock->m_nStartPos ) ||
152                     ( nStart < pLock->m_nEndPos && nEnd > pLock->m_nEndPos ) )
153                     return sal_False;
154             }
155         }
156     }
157     pLock  = new InternalStreamLock( nStart, nEnd, pStream );
158     return sal_True;
159 }
160 
161 void InternalStreamLock::UnlockFile( sal_Size nStart, sal_Size nEnd, SvFileStream* pStream )
162 {
163 #ifndef BOOTSTRAP
164     vos:: OGuard  aGuard( LockMutex::get() );
165 #endif
166     InternalStreamLock* pLock = NULL;
167     InternalStreamLockList &rLockList = LockList::get();
168     if( nStart == 0 && nEnd == 0 )
169     {
170         for( sal_uIntPtr i = 0; i < rLockList.Count(); ++i )
171         {
172             if( ( pLock = rLockList.GetObject( i ) )->m_pStream == pStream )
173             {
174                 delete pLock;
175                 i--;
176             }
177         }
178         return;
179     }
180     for( sal_uIntPtr i = 0; i < rLockList.Count(); ++i )
181     {
182         if( ( pLock = rLockList.GetObject( i ) )->m_pStream == pStream &&
183             nStart == pLock->m_nStartPos && nEnd == pLock->m_nEndPos )
184         {
185             delete pLock;
186             return;
187         }
188     }
189 }
190 
191 // --------------
192 // - StreamData -
193 // --------------
194 
195 class StreamData
196 {
197 public:
198     int     nHandle;
199 
200             StreamData() { nHandle = 0; }
201 };
202 
203 // -----------------------------------------------------------------------
204 
205 static sal_uInt32 GetSvError( int nErrno )
206 {
207     static struct { int nErr; sal_uInt32 sv; } errArr[] =
208     {
209         { 0,            SVSTREAM_OK },
210         { EACCES,       SVSTREAM_ACCESS_DENIED },
211         { EBADF,        SVSTREAM_INVALID_HANDLE },
212 #if defined( RS6000 ) || defined( ALPHA ) || defined( HP9000 ) || defined( NETBSD ) || defined(FREEBSD) || defined(MACOSX) || defined(__FreeBSD_kernel__)
213         { EDEADLK,      SVSTREAM_LOCKING_VIOLATION },
214 #else
215         { EDEADLOCK,    SVSTREAM_LOCKING_VIOLATION },
216 #endif
217         { EINVAL,       SVSTREAM_INVALID_PARAMETER },
218         { EMFILE,       SVSTREAM_TOO_MANY_OPEN_FILES },
219         { ENFILE,       SVSTREAM_TOO_MANY_OPEN_FILES },
220         { ENOENT,       SVSTREAM_FILE_NOT_FOUND },
221         { EPERM,        SVSTREAM_ACCESS_DENIED },
222         { EROFS,        SVSTREAM_ACCESS_DENIED },
223         { EAGAIN,       SVSTREAM_LOCKING_VIOLATION },
224         { EISDIR,       SVSTREAM_PATH_NOT_FOUND },
225         { ELOOP,        SVSTREAM_PATH_NOT_FOUND },
226 #if ! defined( RS6000 ) && ! defined( ALPHA ) && ! defined( NETBSD ) && ! defined (FREEBSD) && ! defined (MACOSX) && ! defined(__FreeBSD_kernel__)
227         { EMULTIHOP,    SVSTREAM_PATH_NOT_FOUND },
228         { ENOLINK,      SVSTREAM_PATH_NOT_FOUND },
229 #endif
230         { ENOTDIR,      SVSTREAM_PATH_NOT_FOUND },
231         { ETXTBSY,      SVSTREAM_ACCESS_DENIED  },
232         { EEXIST,       SVSTREAM_CANNOT_MAKE    },
233         { ENOSPC,       SVSTREAM_DISK_FULL      },
234         { (int)0xFFFF,  SVSTREAM_GENERALERROR }
235     };
236 
237     sal_uInt32 nRetVal = SVSTREAM_GENERALERROR;    // Standardfehler
238     int i=0;
239     do
240     {
241         if ( errArr[i].nErr == nErrno )
242         {
243             nRetVal = errArr[i].sv;
244             break;
245         }
246         ++i;
247     }
248     while( errArr[i].nErr != 0xFFFF );
249     return nRetVal;
250 }
251 
252 /*************************************************************************
253 |*
254 |*    SvFileStream::SvFileStream()
255 |*
256 |*    Beschreibung      STREAM.SDW
257 |*    Ersterstellung    OV 08.06.94
258 |*    Letzte Aenderung  OV 08.06.94
259 |*
260 *************************************************************************/
261 
262 SvFileStream::SvFileStream( const String& rFileName, StreamMode nOpenMode )
263 {
264     bIsOpen             = sal_False;
265     nLockCounter        = 0;
266     bIsWritable         = sal_False;
267     pInstanceData       = new StreamData;
268 
269     SetBufferSize( 1024 );
270     // convert URL to SystemPath, if necessary
271     ::rtl::OUString aSystemFileName;
272     if( FileBase::getSystemPathFromFileURL( rFileName , aSystemFileName )
273         != FileBase::E_None )
274     {
275         aSystemFileName = rFileName;
276     }
277     Open( aSystemFileName, nOpenMode );
278 }
279 
280 /*************************************************************************
281 |*
282 |*    SvFileStream::SvFileStream()
283 |*
284 |*    Beschreibung      STREAM.SDW
285 |*    Ersterstellung    OV 22.11.94
286 |*    Letzte Aenderung  OV 22.11.94
287 |*
288 *************************************************************************/
289 
290 SvFileStream::SvFileStream()
291 {
292     bIsOpen             = sal_False;
293     nLockCounter        = 0;
294     bIsWritable         = sal_False;
295     pInstanceData       = new StreamData;
296     SetBufferSize( 1024 );
297 }
298 
299 /*************************************************************************
300 |*
301 |*    SvFileStream::~SvFileStream()
302 |*
303 |*    Beschreibung      STREAM.SDW
304 |*    Ersterstellung    OV 22.11.94
305 |*    Letzte Aenderung  OV 22.11.94
306 |*
307 *************************************************************************/
308 
309 SvFileStream::~SvFileStream()
310 {
311     Close();
312 
313     InternalStreamLock::UnlockFile( 0, 0, this );
314 
315     if (pInstanceData)
316         delete pInstanceData;
317 }
318 
319 /*************************************************************************
320 |*
321 |*    SvFileStream::GetFileHandle()
322 |*
323 |*    Beschreibung      STREAM.SDW
324 |*    Ersterstellung    OV 22.11.94
325 |*    Letzte Aenderung  OV 22.11.94
326 |*
327 *************************************************************************/
328 
329 sal_uInt32 SvFileStream::GetFileHandle() const
330 {
331     return (sal_uInt32)pInstanceData->nHandle;
332 }
333 
334 /*************************************************************************
335 |*
336 |*    SvFileStream::IsA()
337 |*
338 |*    Beschreibung      STREAM.SDW
339 |*    Ersterstellung    OV 14.06.94
340 |*    Letzte Aenderung  OV 14.06.94
341 |*
342 *************************************************************************/
343 
344 sal_uInt16 SvFileStream::IsA() const
345 {
346     return ID_FILESTREAM;
347 }
348 
349 /*************************************************************************
350 |*
351 |*    SvFileStream::GetData()
352 |*
353 |*    Beschreibung      STREAM.SDW
354 |*    Ersterstellung    OV 15.06.94
355 |*    Letzte Aenderung  OV 15.06.94
356 |*
357 *************************************************************************/
358 
359 sal_Size SvFileStream::GetData( void* pData, sal_Size nSize )
360 {
361 #ifdef DBG_UTIL
362     ByteString aTraceStr( "SvFileStream::GetData(): " );
363     aTraceStr += ByteString::CreateFromInt64(nSize);
364     aTraceStr += " Bytes from ";
365     aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
366     DBG_TRACE( aTraceStr.GetBuffer() );
367 #endif
368 
369     int nRead = 0;
370     if ( IsOpen() )
371     {
372         nRead = read(pInstanceData->nHandle,pData,(unsigned)nSize);
373         if ( nRead == -1 )
374             SetError( ::GetSvError( errno ));
375     }
376     return (sal_Size)nRead;
377 }
378 
379 /*************************************************************************
380 |*
381 |*    SvFileStream::PutData()
382 |*
383 |*    Beschreibung      STREAM.SDW
384 |*    Ersterstellung    OV 15.06.94
385 |*    Letzte Aenderung  OV 15.06.94
386 |*
387 *************************************************************************/
388 
389 sal_Size SvFileStream::PutData( const void* pData, sal_Size nSize )
390 {
391 #ifdef DBG_UTIL
392     ByteString aTraceStr( "SvFileStrean::PutData: " );
393     aTraceStr += ByteString::CreateFromInt64(nSize);
394     aTraceStr += " Bytes to ";
395     aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
396     DBG_TRACE( aTraceStr.GetBuffer() );
397 #endif
398 
399     int nWrite = 0;
400     if ( IsOpen() )
401     {
402         nWrite = write(pInstanceData->nHandle,pData,(unsigned)nSize);
403         if ( nWrite == -1 )
404         SetError( ::GetSvError( errno ) );
405         else if( !nWrite )
406         SetError( SVSTREAM_DISK_FULL );
407     }
408     return (sal_Size)nWrite;
409 }
410 
411 /*************************************************************************
412 |*
413 |*    SvFileStream::SeekPos()
414 |*
415 |*    Beschreibung      STREAM.SDW
416 |*    Ersterstellung    OV 15.06.94
417 |*    Letzte Aenderung  OV 15.06.94
418 |*
419 *************************************************************************/
420 
421 sal_Size SvFileStream::SeekPos( sal_Size nPos )
422 {
423     if ( IsOpen() )
424     {
425         long nNewPos;
426         if ( nPos != STREAM_SEEK_TO_END )
427             nNewPos = lseek( pInstanceData->nHandle, (long)nPos, SEEK_SET );
428         else
429             nNewPos = lseek( pInstanceData->nHandle, 0L, SEEK_END );
430 
431         if ( nNewPos == -1 )
432         {
433             SetError( SVSTREAM_SEEK_ERROR );
434             return 0L;
435         }
436         // langsam aber sicherer als return nNewPos
437         return lseek(pInstanceData->nHandle,0L,SEEK_CUR);
438         // return nNewPos;
439     }
440     SetError( SVSTREAM_GENERALERROR );
441     return 0L;
442 }
443 
444 
445 /*************************************************************************
446 |*
447 |*    SvFileStream::FlushData()
448 |*
449 |*    Beschreibung      STREAM.SDW
450 |*    Ersterstellung    OV 15.06.94
451 |*    Letzte Aenderung  OV 15.06.94
452 |*
453 *************************************************************************/
454 
455 void SvFileStream::FlushData()
456 {
457 // lokal gibt es nicht
458 }
459 
460 static char *pFileLockEnvVar = (char*)1;
461 
462 /*************************************************************************
463 |*
464 |*    SvFileStream::LockRange()
465 |*
466 |*    Beschreibung      STREAM.SDW
467 |*    Ersterstellung    OV 15.06.94
468 |*    Letzte Aenderung  OV 15.06.94
469 |*
470 *************************************************************************/
471 
472 sal_Bool SvFileStream::LockRange( sal_Size nByteOffset, sal_Size nBytes )
473 {
474     struct flock aflock;
475     aflock.l_start = nByteOffset;
476     aflock.l_whence = SEEK_SET;
477     aflock.l_len = nBytes;
478 
479     int nLockMode = 0;
480 
481     if ( ! IsOpen() )
482         return sal_False;
483 
484     if ( eStreamMode & STREAM_SHARE_DENYALL )
485         {
486         if (bIsWritable)
487             nLockMode = F_WRLCK;
488         else
489             nLockMode = F_RDLCK;
490         }
491 
492     if ( eStreamMode & STREAM_SHARE_DENYREAD )
493         {
494         if (bIsWritable)
495             nLockMode = F_WRLCK;
496         else
497         {
498             SetError(SVSTREAM_LOCKING_VIOLATION);
499             return sal_False;
500         }
501         }
502 
503     if ( eStreamMode & STREAM_SHARE_DENYWRITE )
504         {
505         if (bIsWritable)
506             nLockMode = F_WRLCK;
507         else
508             nLockMode = F_RDLCK;
509         }
510 
511     if (!nLockMode)
512         return sal_True;
513 
514     if( ! InternalStreamLock::LockFile( nByteOffset, nByteOffset+nBytes, this ) )
515     {
516 #if OSL_DEBUG_LEVEL > 1
517         fprintf( stderr, "InternalLock on %s [ %ld ... %ld ] failed\n",
518                  ByteString(aFilename, osl_getThreadTextEncoding()).GetBuffer(), nByteOffset, nByteOffset+nBytes );
519 #endif
520         return sal_False;
521     }
522 
523     // HACK: File-Locking nur via Environmentvariable einschalten
524     // um einen Haenger im Zusammenspiel mit einem Linux
525     // NFS-2-Server (kein Lockdaemon) zu verhindern.
526     // File-Locking ?ber NFS ist generell ein Performancekiller.
527     //                      HR, 22.10.1997 fuer SOLARIS
528     //                      CP, 30.11.1997 fuer HPUX
529     //                      ER, 18.12.1997 fuer IRIX
530     //                      HR, 18.05.1998 Environmentvariable
531 
532     if ( pFileLockEnvVar == (char*)1 )
533         pFileLockEnvVar = getenv("STAR_ENABLE_FILE_LOCKING");
534     if ( ! pFileLockEnvVar )
535         return sal_True;
536 
537     aflock.l_type = nLockMode;
538     if (fcntl(pInstanceData->nHandle, F_GETLK, &aflock) == -1)
539     {
540     #if ( defined HPUX && defined BAD_UNION )
541     #ifdef DBG_UTIL
542         fprintf( stderr, "***** FCNTL(lock):errno = %d\n", errno );
543     #endif
544         if ( errno == EINVAL || errno == ENOSYS )
545             return sal_True;
546     #endif
547     #if defined SINIX
548         if (errno == EINVAL)
549             return sal_True;
550     #endif
551     #if defined SOLARIS
552         if (errno == ENOSYS)
553             return sal_True;
554     #endif
555         SetError( ::GetSvError( errno ));
556         return sal_False;
557     }
558     if (aflock.l_type != F_UNLCK)
559     {
560         SetError(SVSTREAM_LOCKING_VIOLATION);
561         return sal_False;
562     }
563 
564     aflock.l_type = nLockMode;
565     if (fcntl(pInstanceData->nHandle, F_SETLK, &aflock) == -1)
566     {
567         SetError( ::GetSvError( errno ));
568         return sal_False;
569     }
570     return sal_True;
571 }
572 
573 /*************************************************************************
574 |*
575 |*    SvFileStream::UnlockRange()
576 |*
577 |*    Beschreibung      STREAM.SDW
578 |*    Ersterstellung    OV 15.06.94
579 |*    Letzte Aenderung  OV 15.06.94
580 |*
581 *************************************************************************/
582 
583 sal_Bool SvFileStream::UnlockRange( sal_Size nByteOffset, sal_Size nBytes )
584 {
585 
586     struct flock aflock;
587     aflock.l_type = F_UNLCK;
588     aflock.l_start = nByteOffset;
589     aflock.l_whence = SEEK_SET;
590     aflock.l_len = nBytes;
591 
592     if ( ! IsOpen() )
593         return sal_False;
594 
595     InternalStreamLock::UnlockFile( nByteOffset, nByteOffset+nBytes, this );
596 
597     if ( ! (eStreamMode &
598         (STREAM_SHARE_DENYALL | STREAM_SHARE_DENYREAD | STREAM_SHARE_DENYWRITE)))
599         return sal_True;
600 
601     // wenn File Locking ausgeschaltet, siehe SvFileStream::LockRange
602     if ( ! pFileLockEnvVar )
603         return sal_True;
604 
605     if (fcntl(pInstanceData->nHandle, F_SETLK, &aflock) != -1)
606         return sal_True;
607 
608 #if ( defined HPUX && defined BAD_UNION )
609 #ifdef DBG_UTIL
610         fprintf( stderr, "***** FCNTL(unlock):errno = %d\n", errno );
611 #endif
612         if ( errno == EINVAL || errno == ENOSYS )
613             return sal_True;
614 #endif
615 #if ( defined SINIX )
616     if (errno == EINVAL)
617         return sal_True;
618 #endif
619 
620     SetError( ::GetSvError( errno ));
621     return sal_False;
622 }
623 
624 /*************************************************************************
625 |*
626 |*    SvFileStream::LockFile()
627 |*
628 |*    Beschreibung      STREAM.SDW
629 |*    Ersterstellung    OV 15.06.94
630 |*    Letzte Aenderung  OV 15.06.94
631 |*
632 *************************************************************************/
633 
634 sal_Bool SvFileStream::LockFile()
635 {
636   return LockRange( 0UL, 0UL );
637 }
638 
639 /*************************************************************************
640 |*
641 |*    SvFileStream::UnlockFile()
642 |*
643 |*    Beschreibung      STREAM.SDW
644 |*    Ersterstellung    OV 15.06.94
645 |*    Letzte Aenderung  OV 15.06.94
646 |*
647 *************************************************************************/
648 
649 sal_Bool SvFileStream::UnlockFile()
650 {
651     return UnlockRange( 0UL, 0UL );
652 }
653 
654 /*************************************************************************
655 |*
656 |*    SvFileStream::Open()
657 |*
658 |*    Beschreibung      STREAM.SDW
659 |*    Ersterstellung    OV 15.06.94
660 |*    Letzte Aenderung  OV 15.06.94
661 |*
662 *************************************************************************/
663 
664 void SvFileStream::Open( const String& rFilename, StreamMode nOpenMode )
665 {
666     int nAccess, nAccessRW;
667     int nMode;
668     int nHandleTmp;
669     struct stat buf;
670     sal_Bool bStatValid = sal_False;
671 
672     Close();
673     errno = 0;
674     eStreamMode = nOpenMode;
675     eStreamMode &= ~STREAM_TRUNC; // beim ReOpen nicht cutten
676 
677 //    !!! NoOp: Ansonsten ToAbs() verwendern
678 //    !!! DirEntry aDirEntry( rFilename );
679 //    !!! aFilename = aDirEntry.GetFull();
680     aFilename = rFilename;
681 #ifndef BOOTSTRAP
682     FSysRedirector::DoRedirect( aFilename );
683 #endif
684     ByteString aLocalFilename(aFilename, osl_getThreadTextEncoding());
685 
686 #ifdef DBG_UTIL
687     ByteString aTraceStr( "SvFileStream::Open(): " );
688     aTraceStr +=  aLocalFilename;
689     DBG_TRACE( aTraceStr.GetBuffer() );
690 #endif
691 
692     if ( lstat( aLocalFilename.GetBuffer(), &buf ) == 0 )
693       {
694         bStatValid = sal_True;
695         // SvFileStream soll kein Directory oeffnen
696         if( S_ISDIR( buf.st_mode ) )
697           {
698             SetError( ::GetSvError( EISDIR ) );
699             return;
700           }
701       }
702 
703 
704     if ( !( nOpenMode & STREAM_WRITE ) )
705         nAccessRW = O_RDONLY;
706     else if ( !( nOpenMode & STREAM_READ ) )
707         nAccessRW = O_WRONLY;
708     else
709         nAccessRW = O_RDWR;
710 
711     nAccess = 0;
712     // Fix (MDA, 18.01.95): Bei RD_ONLY nicht mit O_CREAT oeffnen
713     // Wichtig auf Read-Only-Dateisystemen (wie CDROM)
714     if ( (!( nOpenMode & STREAM_NOCREATE )) && ( nAccessRW != O_RDONLY ) )
715         nAccess |= O_CREAT;
716     if ( nOpenMode & STREAM_TRUNC )
717         nAccess |= O_TRUNC;
718 
719     nMode = S_IREAD | S_IROTH | S_IRGRP;
720     if ( nOpenMode & STREAM_WRITE)
721     {
722       nMode |= (S_IWRITE | S_IWOTH | S_IWGRP);
723 
724       if ( nOpenMode & STREAM_COPY_ON_SYMLINK )
725         {
726           if ( bStatValid  &&  S_ISLNK( buf.st_mode ) < 0 )
727             {
728               char *pBuf = new char[ 1024+1 ];
729               if ( readlink( aLocalFilename.GetBuffer(), pBuf, 1024 ) > 0 )
730                 {
731                   if (  unlink(aLocalFilename.GetBuffer())  == 0 )
732                     {
733 #ifdef DBG_UTIL
734                       fprintf( stderr,
735                                "Copying file on symbolic link (%s).\n",
736                                aLocalFilename.GetBuffer() );
737 #endif
738                       String aTmpString( pBuf, osl_getThreadTextEncoding() );
739                       const DirEntry aSourceEntry( aTmpString );
740                       const DirEntry aTargetEntry( aFilename );
741                       FileCopier aFileCopier( aSourceEntry, aTargetEntry );
742                       aFileCopier.Execute();
743                     }
744                 }
745               delete [] pBuf;
746             }
747         }
748     }
749 
750 
751     nHandleTmp = open(aLocalFilename.GetBuffer(),nAccessRW|nAccess, nMode );
752 
753     if ( nHandleTmp == -1 )
754     {
755         if ( nAccessRW != O_RDONLY )
756         {
757             // auf Lesen runterschalten
758             nAccessRW = O_RDONLY;
759             nAccess = 0;
760             nMode = S_IREAD | S_IROTH | S_IRGRP;
761             nHandleTmp =open( aLocalFilename.GetBuffer(),
762                               nAccessRW|nAccess,
763                               nMode );
764             }
765     }
766     if ( nHandleTmp != -1 )
767     {
768         pInstanceData->nHandle = nHandleTmp;
769         bIsOpen = sal_True;
770         if ( nAccessRW != O_RDONLY )
771             bIsWritable = sal_True;
772 
773         if ( !LockFile() ) // ganze Datei
774         {
775             close( nHandleTmp );
776             bIsOpen = sal_False;
777             bIsWritable = sal_False;
778             pInstanceData->nHandle = 0;
779         }
780     }
781     else
782         SetError( ::GetSvError( errno ) );
783 }
784 
785 /*************************************************************************
786 |*
787 |*    SvFileStream::ReOpen()
788 |*
789 |*    Beschreibung      STREAM.SDW
790 |*    Ersterstellung    OV 15.06.94
791 |*    Letzte Aenderung  OV 15.06.94
792 |*
793 *************************************************************************/
794 
795 void SvFileStream::ReOpen()
796 {
797     if ( !bIsOpen && aFilename.Len() )
798         Open( aFilename, eStreamMode );
799 }
800 
801 /*************************************************************************
802 |*
803 |*    SvFileStream::Close()
804 |*
805 |*    Beschreibung      STREAM.SDW
806 |*    Ersterstellung    OV 15.06.94
807 |*    Letzte Aenderung  OV 15.06.94
808 |*
809 *************************************************************************/
810 
811 void SvFileStream::Close()
812 {
813     InternalStreamLock::UnlockFile( 0, 0, this );
814 
815   if ( IsOpen() )
816     {
817 #ifdef DBG_UTIL
818         ByteString aTraceStr( "SvFileStream::Close(): " );
819         aTraceStr += ByteString(aFilename, osl_getThreadTextEncoding());
820         DBG_TRACE( aTraceStr.GetBuffer() );
821 #endif
822 
823         Flush();
824         close( pInstanceData->nHandle );
825         pInstanceData->nHandle = 0;
826     }
827 
828     bIsOpen     = sal_False;
829     bIsWritable = sal_False;
830     SvStream::ClearBuffer();
831     SvStream::ClearError();
832 }
833 
834 /*************************************************************************
835 |*
836 |*    SvFileStream::ResetError()
837 |*
838 |*    Beschreibung      STREAM.SDW; Setzt Filepointer auf Dateianfang
839 |*    Ersterstellung    OV 15.06.94
840 |*    Letzte Aenderung  OV 15.06.94
841 |*
842 *************************************************************************/
843 
844 void SvFileStream::ResetError()
845 {
846     SvStream::ClearError();
847 }
848 
849 
850 /*************************************************************************
851 |*
852 |*    SvFileStream::SetSize()
853 |*
854 |*    Beschreibung      STREAM.SDW;
855 |*    Ersterstellung    OV 15.06.94
856 |*    Letzte Aenderung  OV 15.06.94
857 |*
858 *************************************************************************/
859 
860 void SvFileStream::SetSize (sal_Size nSize)
861 {
862     if (IsOpen())
863     {
864         int fd = pInstanceData->nHandle;
865         if (::ftruncate (fd, (off_t)nSize) < 0)
866         {
867             // Save original error.
868             sal_uInt32 nErr = ::GetSvError (errno);
869 
870             // Check against current size. Fail upon 'shrink'.
871             struct stat aStat;
872             if (::fstat (fd, &aStat) < 0)
873             {
874                 SetError (nErr);
875                 return;
876             }
877             if ((sal::static_int_cast< sal_sSize >(nSize) <= aStat.st_size))
878             {
879                 // Failure upon 'shrink'. Return original error.
880                 SetError (nErr);
881                 return;
882             }
883 
884             // Save current position.
885             sal_Size nCurPos = (sal_Size)::lseek (fd, (off_t)0, SEEK_CUR);
886             if (nCurPos == (sal_Size)(-1))
887             {
888                 SetError (nErr);
889                 return;
890             }
891 
892             // Try 'expand' via 'lseek()' and 'write()'.
893             if (::lseek (fd, (off_t)(nSize - 1), SEEK_SET) < 0)
894             {
895                 SetError (nErr);
896                 return;
897             }
898             if (::write (fd, (char*)"", (size_t)1) < 0)
899             {
900                 // Failure. Restore saved position.
901                 if (::lseek (fd, (off_t)nCurPos, SEEK_SET) < 0)
902                 {
903                     // Double failure.
904                 }
905 
906                 SetError (nErr);
907                 return;
908             }
909 
910             // Success. Restore saved position.
911             if (::lseek (fd, (off_t)nCurPos, SEEK_SET) < 0)
912             {
913                 SetError (nErr);
914                 return;
915             }
916         }
917     }
918 }
919 
920 
921