blob: 3bcba13a2135606d16cc035ab3587df761b063bc [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_tools.hxx"
#if !defined UNX
#include <io.h>
#include <process.h>
#endif
#if defined(UNX) || defined(OS2)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <tools/debug.hxx>
#include <tools/list.hxx>
#include "comdep.hxx"
#include <tools/fsys.hxx>
#define _TOOLS_HXX
#include <tools/urlobj.hxx>
#ifdef UNX
#define _MAX_PATH 260
#endif
#include <tools/stream.hxx>
#ifndef _VOS_MUTEX_HXX
#include <vos/mutex.hxx>
#endif
#include <osl/file.hxx>
#include <rtl/instance.hxx>
using namespace osl;
using namespace rtl;
int ApiRet2ToSolarError_Impl( int nApiRet );
//--------------------------------------------------------------------
int Sys2SolarError_Impl( int nSysErr )
{
switch ( nSysErr )
{
#ifdef WNT
case NO_ERROR: return ERRCODE_NONE;
case ERROR_INVALID_FUNCTION: return ERRCODE_IO_GENERAL;
case ERROR_FILE_NOT_FOUND: return ERRCODE_IO_NOTEXISTS;
case ERROR_PATH_NOT_FOUND: return ERRCODE_IO_NOTEXISTSPATH;
case ERROR_TOO_MANY_OPEN_FILES: return ERRCODE_IO_TOOMANYOPENFILES;
case ERROR_ACCESS_DENIED: return ERRCODE_IO_ACCESSDENIED;
case ERROR_INVALID_HANDLE: return ERRCODE_IO_GENERAL;
case ERROR_NOT_ENOUGH_MEMORY: return ERRCODE_IO_OUTOFMEMORY;
case ERROR_INVALID_BLOCK: return ERRCODE_IO_GENERAL;
// case ERROR_BAD_ENVIRONMENT: return ERRCODE_IO_;
case ERROR_BAD_FORMAT: return ERRCODE_IO_WRONGFORMAT;
case ERROR_INVALID_ACCESS: return ERRCODE_IO_ACCESSDENIED;
// case ERROR_INVALID_DATA: return ERRCODE_IO_;
case ERROR_INVALID_DRIVE: return ERRCODE_IO_INVALIDDEVICE;
case ERROR_CURRENT_DIRECTORY: return ERRCODE_IO_CURRENTDIR;
case ERROR_NOT_SAME_DEVICE: return ERRCODE_IO_NOTSAMEDEVICE;
// case ERROR_NO_MORE_FILES: return ERRCODE_IO_;
case ERROR_WRITE_PROTECT: return ERRCODE_IO_CANTWRITE;
case ERROR_BAD_UNIT: return ERRCODE_IO_INVALIDDEVICE;
case ERROR_NOT_READY: return ERRCODE_IO_DEVICENOTREADY;
case ERROR_BAD_COMMAND: return ERRCODE_IO_GENERAL;
case ERROR_CRC: return ERRCODE_IO_BADCRC;
case ERROR_BAD_LENGTH: return ERRCODE_IO_INVALIDLENGTH;
case ERROR_SEEK: return ERRCODE_IO_CANTSEEK;
case ERROR_NOT_DOS_DISK: return ERRCODE_IO_WRONGFORMAT;
case ERROR_SECTOR_NOT_FOUND: return ERRCODE_IO_GENERAL;
case ERROR_WRITE_FAULT: return ERRCODE_IO_CANTWRITE;
case ERROR_READ_FAULT: return ERRCODE_IO_CANTREAD;
case ERROR_GEN_FAILURE: return ERRCODE_IO_GENERAL;
case ERROR_SHARING_VIOLATION: return ERRCODE_IO_LOCKVIOLATION;
case ERROR_LOCK_VIOLATION: return ERRCODE_IO_LOCKVIOLATION;
case ERROR_WRONG_DISK: return ERRCODE_IO_INVALIDDEVICE;
case ERROR_NOT_SUPPORTED: return ERRCODE_IO_NOTSUPPORTED;
#else
case 0: return ERRCODE_NONE;
case ENOENT: return ERRCODE_IO_NOTEXISTS;
case EACCES: return ERRCODE_IO_ACCESSDENIED;
case EEXIST: return ERRCODE_IO_ALREADYEXISTS;
case EINVAL: return ERRCODE_IO_INVALIDPARAMETER;
case EMFILE: return ERRCODE_IO_TOOMANYOPENFILES;
case ENOMEM: return ERRCODE_IO_OUTOFMEMORY;
case ENOSPC: return ERRCODE_IO_OUTOFSPACE;
#endif
}
DBG_TRACE1( "FSys: unknown system error %d occured", nSysErr );
return FSYS_ERR_UNKNOWN;
}
//--------------------------------------------------------------------
#ifndef BOOTSTRAP
FSysRedirector* FSysRedirector::_pRedirector = 0;
sal_Bool FSysRedirector::_bEnabled = sal_True;
#ifdef UNX
sal_Bool bInRedirection = sal_True;
#else
sal_Bool bInRedirection = sal_False;
#endif
static vos:: OMutex * pRedirectMutex = 0;
//------------------------------------------------------------------------
void FSysRedirector::Register( FSysRedirector *pRedirector )
{
if ( pRedirector )
pRedirectMutex = new vos:: OMutex ;
else
DELETEZ( pRedirectMutex );
_pRedirector = pRedirector;
}
//------------------------------------------------------------------------
void FSysRedirector::DoRedirect( String &rPath )
{
String aURL(rPath);
// if redirection is disabled or not even registered do nothing
if ( !_bEnabled || !pRedirectMutex )
return;
// redirect only removable or remote volumes
if ( !IsRedirectable_Impl( ByteString( aURL, osl_getThreadTextEncoding() ) ) )
return;
// Redirection is acessible only by one thread per time
// dont move the guard behind the bInRedirection check!!!
// think of nested calls (when called from callback)
vos:: OGuard aGuard( pRedirectMutex );
// if already in redirection, dont redirect
if ( bInRedirection )
return;
// dont redirect on nested calls
bInRedirection = sal_True;
// convert to URL
#ifndef UNX
for ( sal_Unicode *p = (sal_Unicode*)aURL.GetBuffer(); *p; ++p )
if ( '\\' == *p ) *p = '/';
else if ( ':' == *p ) *p = '|';
#endif
aURL.Insert( String("file:///", osl_getThreadTextEncoding()), 0 );
// do redirection
Redirector();
bInRedirection = sal_False;
return;
}
//------------------------------------------------------------------------
FSysRedirector* FSysRedirector::Redirector()
{
if ( !_pRedirector )
Register( new FSysRedirector );
return _pRedirector;
}
#endif // BOOTSTRAP
//--------------------------------------------------------------------
class DirEntryStack: public List
{
public:
DirEntryStack() {};
~DirEntryStack();
inline void Push( DirEntry *pEntry );
inline DirEntry* Pop();
inline DirEntry* Top();
inline DirEntry* Bottom();
};
inline void DirEntryStack::Push( DirEntry *pEntry )
{
List::Insert( pEntry, LIST_APPEND );
}
inline DirEntry* DirEntryStack::Pop()
{
return (DirEntry*) List::Remove( Count() - 1 );
}
inline DirEntry* DirEntryStack::Top()
{
return (DirEntry*) List::GetObject( Count() - 1 );
}
inline DirEntry* DirEntryStack::Bottom()
{
return (DirEntry*) List::GetObject( 0 );
}
//--------------------------------------------------------------------
DBG_NAME( DirEntry );
/*************************************************************************
|*
|* DirEntry::~DirEntryStack()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MI 04.07.91
|*
*************************************************************************/
DirEntryStack::~DirEntryStack()
{
while ( Count() )
delete Pop();
}
/*************************************************************************
|*
|* ImpCheckDirEntry()
|*
|* Beschreibung Pruefung eines DirEntry fuer DBG_UTIL
|* Parameter void* p Zeiger auf den DirEntry
|* Return-Wert char* Fehlermeldungs-TExtension oder NULL
|* Ersterstellung MI 16.07.91
|* Letzte Aenderung MI 26.05.93
|*
*************************************************************************/
#ifdef DBG_UTIL
const char* ImpCheckDirEntry( const void* p )
{
DirEntry* p0 = (DirEntry*)p;
if ( p0->pParent )
DBG_CHKOBJ( p0->pParent, DirEntry, ImpCheckDirEntry );
return NULL;
}
#endif
/*************************************************************************
|*
|* ImplCutPath()
|*
|* Beschreibung Fuegt ... ein, damit maximal nMaxChars lang
|* Ersterstellung MI 06.04.94
|* Letzte Aenderung DV 24.06.96
|*
*************************************************************************/
ByteString ImplCutPath( const ByteString& rStr, sal_uInt16 nMax, char cAccDel )
{
sal_uInt16 nMaxPathLen = nMax;
ByteString aCutPath( rStr );
sal_Bool bInsertPrefix = sal_False;
sal_uInt16 nBegin = aCutPath.Search( cAccDel );
if( nBegin == STRING_NOTFOUND )
nBegin = 0;
else
nMaxPathLen += 2; // fuer Prefix <Laufwerk>:
while( aCutPath.Len() > nMaxPathLen )
{
sal_uInt16 nEnd = aCutPath.Search( cAccDel, nBegin + 1 );
sal_uInt16 nCount;
if ( nEnd != STRING_NOTFOUND )
{
nCount = nEnd - nBegin;
aCutPath.Erase( nBegin, nCount );
bInsertPrefix = sal_True;
}
else
break;
}
if ( aCutPath.Len() > nMaxPathLen )
{
for ( sal_uInt16 n = nMaxPathLen; n > nMaxPathLen/2; --n )
if ( !ByteString(aCutPath.GetChar(n)).IsAlphaNumericAscii() )
{
aCutPath.Erase( n );
aCutPath += "...";
break;
}
}
if ( bInsertPrefix )
{
ByteString aIns( cAccDel );
aIns += "...";
aCutPath.Insert( aIns, nBegin );
}
return aCutPath;
}
/*************************************************************************
|*
|* DirEntry::ImpParseOs2Name()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MI 23.06.95
|*
*************************************************************************/
FSysError DirEntry::ImpParseOs2Name( const ByteString& rPfad, FSysPathStyle eStyle )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
// die einzelnen Namen auf einen Stack packen
String aPfad( rPfad, osl_getThreadTextEncoding() );
DirEntryStack aStack;
do
{
// den Namen vor dem ersten "\\" abspalten,
// falls '\\' am Anfang, ist der Name '\\',
// der Rest immer ohne die fuehrenden '\\'.
// ein ":" trennt ebenfalls, gehoert aber zum Namen
// den ersten '\\', '/' oder ':' suchen
sal_uInt16 nPos;
for ( nPos = 0;
nPos < aPfad.Len() && //?O
aPfad.GetChar(nPos) != '\\' && aPfad.GetChar(nPos) != '/' && //?O
aPfad.GetChar(nPos) != ':'; //?O
nPos++ )
/* do nothing */;
// ist der Name ein UNC Pathname?
if ( nPos == 0 && aPfad.Len() > 1 &&
( ( aPfad.GetChar(0) == '\\' && aPfad.GetChar(1) == '\\' ) ||
( aPfad.GetChar(0) == '/' && aPfad.GetChar(1) == '/' ) ) )
{
for ( nPos = 2; aPfad.Len() > nPos; ++nPos )
if ( aPfad.GetChar(nPos) == '\\' || aPfad.GetChar(nPos) == '/' )
break;
aName = ByteString( aPfad.Copy( 2, nPos-2 ), osl_getThreadTextEncoding() );
aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT, eStyle ) );
}
// ist der Name die Root des aktuellen Drives?
else if ( nPos == 0 && aPfad.Len() > 0 &&
( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) )
{
// Root-Directory des aktuellen Drives
aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) );
}
else
{
// ist der Name ein Drive?
if ( nPos < aPfad.Len() && aPfad.GetChar(nPos) == ':' )
{
aName = ByteString( aPfad.Copy( 0, nPos + 1 ), osl_getThreadTextEncoding() );
// ist der Name die Root des Drives
if ( (nPos + 1) < aPfad.Len() &&
( aPfad.GetChar(nPos+1) == '\\' || aPfad.GetChar(nPos+1) == '/' ) )
{
// schon was auf dem Stack?
// oder Novell-Format? (not supported wegen URLs)
if ( aStack.Count() || aName.Len() > 2 )
{
aName = rPfad;
return FSYS_ERR_MISPLACEDCHAR;
}
// Root-Directory des Drive
aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT, eStyle ) );
}
else
{
// liegt ein anderes Drive auf dem Stack?
if ( aStack.Count() &&
COMPARE_EQUAL != aStack.Bottom()->aName.CompareIgnoreCaseToAscii(aName) )
aStack.Clear();
// liegt jetzt nichts mehr auf dem Stack?
if ( !aStack.Count() )
aStack.Push( new DirEntry( aName, FSYS_FLAG_RELROOT, eStyle ) );
}
}
// es ist kein Drive
else
{
// den Namen ohne Trenner abspalten
aName = ByteString( aPfad.Copy( 0, nPos ), osl_getThreadTextEncoding() );
// stellt der Name die aktuelle Directory dar?
if ( aName == "." )
/* do nothing */;
// stellt der Name die Parent-Directory dar?
else if ( aName == ".." )
{
// ist nichts, ein Parent oder eine relative Root
// auf dem Stack?
if ( ( aStack.Count() == 0 ) ||
( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) ||
( aStack.Top()->eFlag == FSYS_FLAG_RELROOT ) )
// fuehrende Parents kommen auf den Stack
aStack.Push( new DirEntry( FSYS_FLAG_PARENT ) );
// ist es eine absolute Root
else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT )
{
// die hat keine Parent-Directory
aName = rPfad;
return FSYS_ERR_NOTEXISTS;
}
else
// sonst hebt der Parent den TOS auf
delete aStack.Pop();
}
else
{
if ( eStyle == FSYS_STYLE_FAT )
{
// ist der Name grundsaetzlich ungueltig?
int nPunkte = 0;
const char *pChar;
for ( pChar = aName.GetBuffer();
nPunkte < 2 && *pChar != 0;
pChar++ )
{
if ( *pChar == ';' )
nPunkte = 0;
else
nPunkte += ( *pChar == '.' ) ? 1 : 0;
}
if ( nPunkte > 1 )
{
aName = rPfad;
return FSYS_ERR_MISPLACEDCHAR;
}
}
// normalen Entries kommen auf den Stack
DirEntry *pNew = new DirEntry( aName, FSYS_FLAG_NORMAL, eStyle );
if ( !pNew->IsValid() )
{
aName = rPfad;
ErrCode eErr = pNew->GetError();
delete pNew;
return eErr;
}
aStack.Push( pNew );
}
}
}
// den Restpfad bestimmen
aPfad.Erase( 0, nPos + 1 );
while ( aPfad.Len() && ( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) )
aPfad.Erase( 0, 1 );
}
while ( aPfad.Len() );
sal_uIntPtr nErr = ERRCODE_NONE;
// Haupt-Entry (selbst) zuweisen
if ( aStack.Count() == 0 )
{
eFlag = FSYS_FLAG_CURRENT;
aName.Erase();
}
else
{
eFlag = aStack.Top()->eFlag;
aName = aStack.Top()->aName;
nErr = aStack.Top()->nError;
delete aStack.Pop();
}
// die Parent-Entries vom Stack holen
DirEntry** pTemp = &pParent; // Zeiger auf den Member pParent setzen
while ( aStack.Count() )
{
*pTemp = aStack.Pop();
// Zeiger auf den Member pParent des eigenen Parent setzen
pTemp = &( (*pTemp)->pParent );
}
// wird damit ein Volume beschrieben?
if ( !pParent && eFlag == FSYS_FLAG_RELROOT && aName.Len() )
eFlag = FSYS_FLAG_VOLUME;
// bei gesetztem ErrorCode den Namen komplett "ubernehmen
if ( nErr )
aName = rPfad;
return nErr;
}
/*************************************************************************
|*
|* DirEntry::ImpParseName()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.08.91
|* Letzte Aenderung MI 26.05.93
|*
*************************************************************************/
FSysError DirEntry::ImpParseName( const ByteString& rbInitName,
FSysPathStyle eStyle )
{
String rInitName( rbInitName, osl_getThreadTextEncoding() );
if ( eStyle == FSYS_STYLE_HOST )
eStyle = DEFSTYLE;
// KI-Division of FSys
if ( eStyle == FSYS_STYLE_DETECT )
{
sal_Unicode cFirst = rInitName.GetChar(0);
if ( rInitName.Len() == 2 && rInitName.GetChar(1) == ':' &&
((cFirst >= 'A' && cFirst <= 'Z') ||
(cFirst >= 'a' && cFirst <= 'z')))
eStyle = FSYS_STYLE_HPFS;
else if ( rInitName.Len() > 2 && rInitName.GetChar(1) == ':' )
{
if ( rInitName.Search( ':', 2 ) == STRING_NOTFOUND )
eStyle = FSYS_STYLE_HPFS;
else
eStyle = FSYS_STYLE_MAC;
}
else if ( rInitName.Search( '/' ) != STRING_NOTFOUND )
eStyle = FSYS_STYLE_BSD;
else if ( rInitName.Search( '\\' ) != STRING_NOTFOUND )
eStyle = FSYS_STYLE_HPFS;
else if ( rInitName.Search( ':' ) != STRING_NOTFOUND )
eStyle = FSYS_STYLE_MAC;
else
eStyle = FSYS_STYLE_HPFS;
}
switch ( eStyle )
{
case FSYS_STYLE_FAT:
case FSYS_STYLE_VFAT:
case FSYS_STYLE_HPFS:
case FSYS_STYLE_NTFS:
case FSYS_STYLE_NWFS:
return ImpParseOs2Name( rbInitName, eStyle );
case FSYS_STYLE_BSD:
case FSYS_STYLE_SYSV:
return ImpParseUnixName( rbInitName, eStyle );
case FSYS_STYLE_MAC:
return FSYS_ERR_OK;
default:
return FSYS_ERR_UNKNOWN;
}
}
/*************************************************************************
|*
|* GetStyle()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 15.11.91
|* Letzte Aenderung MI 15.11.91
|*
*************************************************************************/
static FSysPathStyle GetStyle( FSysPathStyle eStyle )
{
if ( eStyle == FSYS_STYLE_HOST || eStyle == FSYS_STYLE_DETECT )
return DEFSTYLE;
else
return eStyle;
}
/*************************************************************************
|*
|* DirEntry::ImpTrim()
|*
|* Beschreibung bringt den Namen auf Betriebssystem-Norm
|* z.B. 8.3 lower beim MS-DOS Formatter
|* wirkt nicht rekursiv
|* Ersterstellung MI 12.08.91
|* Letzte Aenderung MI 21.05.92
|*
*************************************************************************/
void DirEntry::ImpTrim( FSysPathStyle eStyle )
{
// Wildcards werden nicht geclipt
if ( ( aName.Search( '*' ) != STRING_NOTFOUND ) ||
( aName.Search( '?' ) != STRING_NOTFOUND ) ||
( aName.Search( ';' ) != STRING_NOTFOUND ) )
return;
switch ( eStyle )
{
case FSYS_STYLE_FAT:
{
sal_uInt16 nPunktPos = aName.Search( '.' );
if ( nPunktPos == STRING_NOTFOUND )
{
if ( aName.Len() > 8 )
{
nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
aName.Erase( 8 );
}
}
else
{
if ( nPunktPos > 8 )
{
nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
aName.Erase( 8, nPunktPos - 8 );
nPunktPos = 8;
}
if ( aName.Len() > nPunktPos + 3 )
{
if ( aName.Len() - nPunktPos > 4 )
{
nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
aName.Erase( nPunktPos + 4 );
}
}
}
aName.ToLowerAscii();
break;
}
case FSYS_STYLE_VFAT:
case FSYS_STYLE_HPFS:
case FSYS_STYLE_NTFS:
case FSYS_STYLE_NWFS:
if ( aName.Len() > 254 )
{
nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
aName.Erase( 254 );
}
if ( eStyle == FSYS_STYLE_HPFS &&
( eFlag == FSYS_FLAG_ABSROOT || eFlag == FSYS_FLAG_RELROOT ) )
aName.ToUpperAscii();
break;
case FSYS_STYLE_SYSV:
if ( aName.Len() > 14 )
{
nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
aName.Erase( 14 );
}
break;
case FSYS_STYLE_BSD:
if ( aName.Len() > 250 )
{
nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
aName.Erase( 250 );
}
break;
case FSYS_STYLE_MAC:
if ( eFlag & ( FSYS_FLAG_ABSROOT | FSYS_FLAG_VOLUME ) )
{
if ( aName.Len() > 27 )
{
nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
aName.Erase( 27 );
}
}
else
{
if ( aName.Len() > 31 )
{
nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
aName.Erase( 31 );
}
}
break;
default:
/* kann nicht sein */;
}
}
/*************************************************************************
|*
|* DirEntry::DirEntry()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry::DirEntry( const ByteString& rName, DirEntryFlag eDirFlag,
FSysPathStyle eStyle ) :
#ifdef FEAT_FSYS_DOUBLESPEED
pStat( 0 ),
#endif
aName( rName )
{
DBG_CTOR( DirEntry, ImpCheckDirEntry );
pParent = NULL;
eFlag = eDirFlag;
nError = FSYS_ERR_OK;
ImpTrim( eStyle );
}
/*************************************************************************
|*
|* DirEntry::DirEntry()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry::DirEntry( const DirEntry& rOrig ) :
#ifdef FEAT_FSYS_DOUBLESPEED
pStat( rOrig.pStat ? new FileStat(*rOrig.pStat) : 0 ),
#endif
aName( rOrig.aName )
{
DBG_CTOR( DirEntry, ImpCheckDirEntry );
eFlag = rOrig.eFlag;
nError = rOrig.nError;
if ( rOrig.pParent )
{
pParent = new DirEntry( *rOrig.pParent );
}
else
{
pParent = NULL;
}
}
/*************************************************************************
|*
|* DirEntry::DirEntry()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry::DirEntry( const String& rInitName, FSysPathStyle eStyle )
#ifdef FEAT_FSYS_DOUBLESPEED
: pStat( 0 )
#endif
{
DBG_CTOR( DirEntry, ImpCheckDirEntry );
pParent = NULL;
// schnelle Loesung fuer Leerstring
if ( !rInitName.Len())
{
eFlag = FSYS_FLAG_CURRENT;
nError = FSYS_ERR_OK;
return;
}
ByteString aTmpName(rInitName, osl_getThreadTextEncoding());
if( eStyle == FSYS_STYLE_URL || aTmpName.CompareIgnoreCaseToAscii("file:",5 ) == COMPARE_EQUAL )
{
#ifndef BOOTSTRAP
DBG_WARNING( "File URLs are not permitted but accepted" );
aTmpName = ByteString(String(INetURLObject( rInitName ).PathToFileName()), osl_getThreadTextEncoding());
eStyle = FSYS_STYLE_HOST;
#endif // BOOTSTRAP
}
else
{
::rtl::OUString aTmp;
::rtl::OUString aOInitName;
if ( FileBase::getFileURLFromSystemPath( OUString( rInitName ), aTmp ) == FileBase::E_None )
{
aOInitName = OUString( rInitName );
aTmpName = ByteString( String(aOInitName), osl_getThreadTextEncoding() );
}
#ifdef DBG_UTIL
// ASF nur bei Default eStyle, nicht z.B. aus MakeShortName()
if( eStyle == FSYS_STYLE_HOST &&
aTmpName.Search( "://" ) != STRING_NOTFOUND )
{
ByteString aErr = "DirEntries akzeptieren nur File URLS: ";
aErr += aTmpName;
DBG_WARNING( aErr.GetBuffer() );
}
#endif
}
nError = ImpParseName( aTmpName, eStyle );
if ( nError != FSYS_ERR_OK )
eFlag = FSYS_FLAG_INVALID;
}
/*************************************************************************/
DirEntry::DirEntry( const ByteString& rInitName, FSysPathStyle eStyle )
#ifdef FEAT_FSYS_DOUBLESPEED
: pStat( 0 )
#endif
{
DBG_CTOR( DirEntry, ImpCheckDirEntry );
pParent = NULL;
// schnelle Loesung fuer Leerstring
if ( !rInitName.Len() )
{
eFlag = FSYS_FLAG_CURRENT;
nError = FSYS_ERR_OK;
return;
}
ByteString aTmpName( rInitName );
if( eStyle == FSYS_STYLE_URL || rInitName.CompareIgnoreCaseToAscii("file:",5 ) == COMPARE_EQUAL )
{
#ifndef BOOTSTRAP
DBG_WARNING( "File URLs are not permitted but accepted" );
aTmpName = ByteString(String(INetURLObject( rInitName ).PathToFileName()), osl_getThreadTextEncoding());
eStyle = FSYS_STYLE_HOST;
#endif
}
#ifdef DBG_UTIL
else
// ASF nur bei Default eStyle, nicht z.B. aus MakeShortName()
if( eStyle == FSYS_STYLE_HOST &&
rInitName.Search( "://" ) != STRING_NOTFOUND )
{
ByteString aErr = "DirEntries akzeptieren nur File URLS: ";
aErr += rInitName;
DBG_WARNING( aErr.GetBuffer() );
}
#endif
nError = ImpParseName( aTmpName, eStyle );
if ( nError != FSYS_ERR_OK )
eFlag = FSYS_FLAG_INVALID;
}
/*************************************************************************
|*
|* DirEntry::DirEntry()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry::DirEntry( DirEntryFlag eDirFlag )
#ifdef FEAT_FSYS_DOUBLESPEED
: pStat( 0 )
#endif
{
DBG_CTOR( DirEntry, ImpCheckDirEntry );
eFlag = eDirFlag;
nError = ( eFlag == FSYS_FLAG_INVALID ) ? FSYS_ERR_UNKNOWN : FSYS_ERR_OK;
pParent = NULL;
}
/*************************************************************************
|*
|* DirEntry::~DirEntry()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry::~DirEntry()
{
DBG_DTOR( DirEntry, ImpCheckDirEntry );
delete pParent;
#ifdef FEAT_FSYS_DOUBLESPEED
delete pStat;
#endif
}
/*************************************************************************
|*
|* DirEntry::ImpGetTopPtr() const
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
const DirEntry* DirEntry::ImpGetTopPtr() const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
const DirEntry *pTemp = this;
while ( pTemp->pParent )
pTemp = pTemp->pParent;
return pTemp;
}
/*************************************************************************
|*
|* DirEntry::ImpGetTopPtr()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 13.11.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry* DirEntry::ImpGetTopPtr()
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
DirEntry *pTemp = this;
while ( pTemp->pParent )
pTemp = pTemp->pParent;
return pTemp;
}
/*************************************************************************
|*
|* DirEntry::ImpGetPreTopPtr()
|*
|* Beschreibung liefert einen Pointer auf den vorletzten Entry
|* Ersterstellung MI 01.11.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry* DirEntry::ImpGetPreTopPtr()
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
DirEntry *pTemp = this;
if ( pTemp->pParent )
{
while ( pTemp->pParent->pParent )
pTemp = pTemp->pParent;
}
return pTemp;
}
/*************************************************************************
|*
|* DirEntry::ImpChangeParent()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MI 21.05.92
|*
*************************************************************************/
DirEntry* DirEntry::ImpChangeParent( DirEntry* pNewParent, sal_Bool bNormalize )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
DirEntry *pTemp = pParent;
if ( bNormalize && pNewParent &&
pNewParent->eFlag == FSYS_FLAG_RELROOT && !pNewParent->aName.Len() )
{
pParent = 0;
delete pNewParent;
}
else
pParent = pNewParent;
return pTemp;
}
/*************************************************************************
|*
|* DirEntry::Exists()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MI 24.09.91
|*
*************************************************************************/
sal_Bool DirEntry::Exists( FSysAccess nAccess ) const
{
#ifndef BOOTSTRAP
static vos::OMutex aLocalMutex;
vos::OGuard aGuard( aLocalMutex );
#endif
if ( !IsValid() )
return sal_False;
#if defined WNT || defined OS2
// spezielle Filenamen sind vom System da
if ( ( aName.CompareIgnoreCaseToAscii("CLOCK$") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("CON") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("AUX") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("COM1") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("COM2") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("COM3") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("COM4") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("LPT1") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("LPT2") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("LPT3") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("NUL") == COMPARE_EQUAL ||
aName.CompareIgnoreCaseToAscii("PRN") == COMPARE_EQUAL ) )
return sal_True;
#endif
FSysFailOnErrorImpl();
DirEntryKind eKind = FileStat( *this, nAccess ).GetKind();
if ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) )
{
return sal_True;
}
#if defined WNT || defined OS2
if ( 0 != ( eKind & FSYS_KIND_DEV ) )
{
return DRIVE_EXISTS( ImpGetTopPtr()->aName.GetChar(0) );
}
#endif
return 0 != ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) );
}
/*************************************************************************
|*
|* DirEntry::First()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 15.01.92
|*
*************************************************************************/
sal_Bool DirEntry::First()
{
FSysFailOnErrorImpl();
String aUniPathName( GetPath().GetFull() );
#ifndef BOOTSTRAP
FSysRedirector::DoRedirect( aUniPathName );
ByteString aPathName(aUniPathName, osl_getThreadTextEncoding());
#else
ByteString aPathName(aUniPathName, gsl_getSystemTextEncoding());
#endif
aPathName = GUI2FSYS( aPathName );
DIR *pDir = opendir( (char*) aPathName.GetBuffer() );
if ( pDir )
{
#ifndef BOOTSTRAP
WildCard aWildeKarte( String(CMP_LOWER( aName ), osl_getThreadTextEncoding()) );
#else
WildCard aWildeKarte( String(CMP_LOWER( aName ), gsl_getSystemTextEncoding()) );
#endif
for ( dirent* pEntry = readdir( pDir );
pEntry;
pEntry = readdir( pDir ) )
{
ByteString aFound( FSYS2GUI( ByteString( pEntry->d_name ) ) );
if ( aWildeKarte.Matches( String(CMP_LOWER( aFound ), osl_getThreadTextEncoding())))
{
aName = aFound;
closedir( pDir );
return sal_True;
}
}
closedir( pDir );
}
return sal_False;
}
/*************************************************************************
|*
|* DirEntry::GetFull()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
String DirEntry::GetFull( FSysPathStyle eStyle, sal_Bool bWithDelimiter,
sal_uInt16 nMaxChars ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
ByteString aRet;
eStyle = GetStyle( eStyle );
if ( pParent )
{
if ( ( pParent->eFlag == FSYS_FLAG_ABSROOT ||
pParent->eFlag == FSYS_FLAG_RELROOT ||
pParent->eFlag == FSYS_FLAG_VOLUME ) )
{
aRet = ByteString(pParent->GetName( eStyle ), osl_getThreadTextEncoding());
aRet += ByteString(GetName( eStyle ), osl_getThreadTextEncoding());
}
else
{
aRet = ByteString(pParent->GetFull( eStyle ), osl_getThreadTextEncoding());
aRet += ACCESSDELIM_C(eStyle);
aRet += ByteString(GetName( eStyle ), osl_getThreadTextEncoding());
}
}
else
{
aRet = ByteString(GetName( eStyle ), osl_getThreadTextEncoding());
}
if ( ( eStyle == FSYS_STYLE_MAC ) &&
( ImpGetTopPtr()->eFlag != FSYS_FLAG_VOLUME ) &&
( ImpGetTopPtr()->eFlag != FSYS_FLAG_ABSROOT ) &&
( aRet.GetChar(0) != ':' ) )
aRet.Insert( ACCESSDELIM_C(eStyle), 0 );
//! Hack
if ( bWithDelimiter )
if ( aRet.GetChar( aRet.Len()-1 ) != ACCESSDELIM_C(eStyle) )
aRet += ACCESSDELIM_C(eStyle);
//! noch ein Hack
if ( nMaxChars < STRING_MAXLEN )
aRet = ImplCutPath( aRet, nMaxChars, ACCESSDELIM_C(eStyle) );
return String(aRet, osl_getThreadTextEncoding());
}
/*************************************************************************
|*
|* DirEntry::GetPath()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry DirEntry::GetPath() const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
if ( pParent )
return DirEntry( *pParent );
return DirEntry();
}
/*************************************************************************
|*
|* DirEntry::GetExtension()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
String DirEntry::GetExtension( char cSep ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
const char *p0 = ( aName.GetBuffer() );
const char *p1 = p0 + aName.Len() - 1;
while ( p1 >= p0 && *p1 != cSep )
p1--;
if ( p1 >= p0 )
// es wurde ein cSep an der Position p1 gefunden
return String(
aName.Copy( static_cast< xub_StrLen >(p1 - p0 + 1) ),
osl_getThreadTextEncoding());
return String();
}
/*************************************************************************
|*
|* DirEntry::GetBase()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
String DirEntry::GetBase( char cSep ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
const char *p0 = ( aName.GetBuffer() );
const char *p1 = p0 + aName.Len() - 1;
while ( p1 >= p0 && *p1 != cSep )
p1--;
if ( p1 >= p0 )
// es wurde ein cSep an der Position p1 gefunden
return String(
aName.Copy( 0, static_cast< xub_StrLen >(p1 - p0) ),
osl_getThreadTextEncoding());
else
// es wurde kein cSep gefunden
return String(aName, osl_getThreadTextEncoding());
}
/*************************************************************************
|*
|* DirEntry::GetName()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91 13:47
|*
*************************************************************************/
String DirEntry::GetName( FSysPathStyle eStyle ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
ByteString aRet;
eStyle = GetStyle( eStyle );
switch( eFlag )
{
case FSYS_FLAG_PARENT:
aRet = ACTPARENT(eStyle);
break;
case FSYS_FLAG_ABSROOT:
{
if ( eStyle == FSYS_STYLE_URL )
{
aRet = "file:///";
aRet += aName;
#ifndef UNX
if ( aName.Len())
{
if ( aName.GetChar(aName.Len()-1) == ':' )
{
aRet.SetChar(aRet.Len()-1, '|');
}
else
{
aRet.Insert( '/', 5 );
}
aRet += "/";
}
#endif
}
else if ( eStyle != FSYS_STYLE_MAC &&
aName.Len() > 1 && aName.GetChar( 1 ) != ':' )
{
// UNC-Pathname
aRet = ACCESSDELIM_C(eStyle);
aRet += ACCESSDELIM_C(eStyle);
aRet += aName ;
aRet += ACCESSDELIM_C(eStyle);
}
else
{
aRet = aName;
aRet += ACCESSDELIM_C(eStyle);
}
break;
}
case FSYS_FLAG_INVALID:
case FSYS_FLAG_VOLUME:
{
if ( eStyle == FSYS_STYLE_URL )
{
aRet = "file:///";
aRet += aName;
#ifndef UNX
if ( aName.Len() && aName.GetChar(aName.Len()-1) == ':' )
{
aRet.SetChar(aRet.Len()-1, '|');
}
#endif
}
else
{
aRet = aName;
}
break;
}
case FSYS_FLAG_RELROOT:
if ( !aName.Len() )
{
aRet = ACTCURRENT(eStyle);
break;
}
default:
aRet = aName;
}
return String(aRet, osl_getThreadTextEncoding());
}
/*************************************************************************
|*
|* DirEntry::IsAbs()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
bool DirEntry::IsAbs() const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
#ifdef UNX
return ( pParent ? pParent->IsAbs() : eFlag == FSYS_FLAG_ABSROOT );
#else
return ( pParent ? pParent->IsAbs() : eFlag == FSYS_FLAG_ABSROOT && aName.Len() > 0 );
#endif
}
/*************************************************************************
|*
|* DirEntry::CutName()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
String DirEntry::CutName( FSysPathStyle eStyle )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
eStyle = GetStyle( eStyle );
String aOldName( GetName( eStyle ) );
if ( pParent )
{
DirEntry *pOldParent = pParent;
if ( pOldParent )
{
pParent = pOldParent->pParent;
eFlag = pOldParent->eFlag;
aName = pOldParent->aName;
pOldParent->pParent = NULL;
delete pOldParent;
}
else
{
eFlag = FSYS_FLAG_CURRENT;
aName.Erase();
}
}
else
{
eFlag = FSYS_FLAG_CURRENT;
aName.Erase();
delete pParent;
pParent = NULL;
}
return aOldName;
}
/*************************************************************************
|*
|* DirEntry::NameCompare
|*
|* Beschreibung Vergleich nur die Namen (ohne Pfad, aber mit Gross/Klein)
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
StringCompare DirEntry::NameCompare( const DirEntry &rWith ) const
{
ByteString aThisName;
ByteString aParameterName;
#ifdef UNX
aThisName = aName;
aParameterName = rWith.aName;
#else
aThisName = ByteString(aName).ToLowerAscii();
aParameterName = ByteString(rWith.aName).ToLowerAscii();
#endif
return aThisName.CompareTo( aParameterName );
}
/*************************************************************************
|*
|* DirEntry::operator==()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
sal_Bool DirEntry::operator==( const DirEntry& rEntry ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
// test wheather the contents are textual the same
if ( nError && ( nError == rEntry.nError ) )
return sal_True;
if ( nError || rEntry.nError ||
( eFlag == FSYS_FLAG_INVALID ) ||
( rEntry.eFlag == FSYS_FLAG_INVALID ) )
return sal_False;
#ifndef OS2
const
#endif
DirEntry *pThis = (DirEntry *)this;
#ifndef OS2
const
#endif
DirEntry *pWith = (DirEntry *)&rEntry;
while( pThis && pWith && (pThis->eFlag == pWith->eFlag) )
{
if ( CMP_LOWER(pThis->aName) != CMP_LOWER(pWith->aName) )
break;
pThis = pThis->pParent;
pWith = pWith->pParent;
}
return ( !pThis && !pWith );
}
/*************************************************************************
|*
|* DirEntry::operator=()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry& DirEntry::operator=( const DirEntry& rEntry )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
if ( this == &rEntry )
return *this;
if ( rEntry.nError != FSYS_ERR_OK ) {
DBG_ERROR("Zuweisung mit invalidem DirEntry");
nError = rEntry.nError;
return *this;
}
// Name und Typ uebernehmen, Refs beibehalten
aName = rEntry.aName;
eFlag = rEntry.eFlag;
nError = FSYS_ERR_OK;
DirEntry *pOldParent = pParent;
if ( rEntry.pParent )
pParent = new DirEntry( *rEntry.pParent );
else
pParent = NULL;
if ( pOldParent )
delete pOldParent;
return *this;
}
/*************************************************************************
|*
|* DirEntry::operator+()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry DirEntry::operator+( const DirEntry& rEntry ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
#ifdef DBG_UTIL
static sal_Bool bTested = sal_False;
if ( !bTested )
{
bTested = sal_True;
FSysTest();
}
#endif
const DirEntry *pEntryTop = rEntry.ImpGetTopPtr();
const DirEntry *pThisTop = ImpGetTopPtr();
// "." + irgendwas oder irgendwas + "d:irgendwas"
/* TPF:org
if ( ( eFlag == FSYS_FLAG_RELROOT && !aName ) ||
( pEntryTop->aName.Len() &&
( pEntryTop->eFlag == FSYS_FLAG_ABSROOT ||
pEntryTop->eFlag == FSYS_FLAG_RELROOT ||
pEntryTop->eFlag == FSYS_FLAG_VOLUME ) ) )
return rEntry;
*/
if (
(eFlag == FSYS_FLAG_RELROOT && !aName.Len()) ||
(
(pEntryTop->aName.Len() ||
((rEntry.Level()>1)?(rEntry[rEntry.Level()-2].aName.CompareIgnoreCaseToAscii(RFS_IDENTIFIER)==COMPARE_EQUAL):sal_False))
&&
(pEntryTop->eFlag == FSYS_FLAG_ABSROOT ||
pEntryTop->eFlag == FSYS_FLAG_RELROOT ||
pEntryTop->eFlag == FSYS_FLAG_VOLUME)
)
)
{
return rEntry;
}
// irgendwas + "." (=> pEntryTop == &rEntry)
if ( pEntryTop->eFlag == FSYS_FLAG_RELROOT && !pEntryTop->aName.Len() )
{
DBG_ASSERT( pEntryTop == &rEntry, "DirEntry::op+ buggy" );
return *this;
}
// root += ".." (=> unmoeglich)
if ( pEntryTop->eFlag == FSYS_FLAG_PARENT && pThisTop == this &&
( eFlag == FSYS_FLAG_ABSROOT ) )
return DirEntry( FSYS_FLAG_INVALID );
// irgendwas += abs (=> nur Device uebernehmen falls vorhanden)
if ( pEntryTop->eFlag == FSYS_FLAG_ABSROOT )
{
ByteString aDevice;
if ( pThisTop->eFlag == FSYS_FLAG_ABSROOT )
aDevice = pThisTop->aName;
DirEntry aRet = rEntry;
if ( aDevice.Len() )
aRet.ImpGetTopPtr()->aName = aDevice;
return aRet;
}
// irgendwas += ".." (=> aufloesen)
if ( eFlag == FSYS_FLAG_NORMAL && pEntryTop->eFlag == FSYS_FLAG_PARENT )
{
String aConcated( GetFull() );
aConcated += ACCESSDELIM_C(FSYS_STYLE_HOST);
aConcated += rEntry.GetFull();
return DirEntry( aConcated );
}
// sonst einfach hintereinander haengen
DirEntry aRet( rEntry );
DirEntry *pTop = aRet.ImpGetTopPtr();
pTop->pParent = new DirEntry( *this );
return aRet;
}
/*************************************************************************
|*
|* DirEntry::operator+=()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
DirEntry &DirEntry::operator+=( const DirEntry& rEntry )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
return *this = *this + rEntry;
}
/*************************************************************************
|*
|* DirEntry::GetAccessDelimiter()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 27.05.93
|* Letzte Aenderung MI 10.06.93
|*
*************************************************************************/
String DirEntry::GetAccessDelimiter( FSysPathStyle eFormatter )
{
return String( ACCESSDELIM_C( GetStyle( eFormatter ) ) );
}
/*************************************************************************
|*
|* DirEntry::SetExtension()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 02.08.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
void DirEntry::SetExtension( const String& rExtension, char cSep )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
// do not set extensions for drives
if(eFlag == FSYS_FLAG_ABSROOT)
{
nError = FSYS_ERR_NOTSUPPORTED;
return;
}
// cSep im Namen suchen
const char *p0 = ( aName.GetBuffer() );
const char *p1 = p0 + aName.Len() - 1;
while ( p1 >= p0 && *p1 != cSep )
p1--;
if ( p1 >= p0 )
{
// es wurde ein cSep an der Position p1 gefunden
aName.Erase(
static_cast< xub_StrLen >(
p1 - p0 + 1 - ( rExtension.Len() ? 0 : 1 )) );
aName += ByteString(rExtension, osl_getThreadTextEncoding());
}
else if ( rExtension.Len() )
{
// es wurde kein cSep gefunden
aName += cSep;
aName += ByteString(rExtension, osl_getThreadTextEncoding());
}
}
/*************************************************************************
|*
|* DirEntry::CutExtension()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 23.07.93
|* Letzte Aenderung MI 23.07.93
|*
*************************************************************************/
String DirEntry::CutExtension( char cSep )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
const char *p0 = ( aName.GetBuffer() );
const char *p1 = p0 + aName.Len() - 1;
while ( p1 >= p0 && *p1 != cSep )
p1--;
if ( p1 >= p0 )
{
// es wurde ein cSep an der Position p1 gefunden
aName.Erase( static_cast< xub_StrLen >(p1-p0) );
return String(p1 + 1, osl_getThreadTextEncoding());
}
return String();
}
/*************************************************************************
|*
|* DirEntry::SetName()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 04.09.93
|* Letzte Aenderung MI 04.09.93
|*
*************************************************************************/
void DirEntry::SetName( const String& rName, FSysPathStyle eFormatter )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
if ( eFormatter == FSYS_STYLE_HOST || eFormatter == FSYS_STYLE_DETECT )
eFormatter = DEFSTYLE;
ByteString aAccDelim( ACCESSDELIM_C( eFormatter ) );
if ( (eFlag != FSYS_FLAG_NORMAL) ||
(aName.Search( ':' ) != STRING_NOTFOUND) ||
(aName.Search( aAccDelim ) != STRING_NOTFOUND) ||
(eFormatter == FSYS_STYLE_FAT && (aName.GetTokenCount( '.' ) > 2) ) )
{
eFlag = FSYS_FLAG_INVALID;
}
else
{
aName = ByteString(rName, osl_getThreadTextEncoding());
}
}
/*************************************************************************
|*
|* DirEntry::Find()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
sal_Bool DirEntry::Find( const String& rPfad, char cDelim )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
if ( ImpGetTopPtr()->eFlag == FSYS_FLAG_ABSROOT )
return sal_True;
sal_Bool bWild = aName.Search( '*' ) != STRING_NOTFOUND ||
aName.Search( '?' ) != STRING_NOTFOUND;
if ( !cDelim )
cDelim = SEARCHDELIM(DEFSTYLE)[0];
sal_uInt16 nTokenCount = rPfad.GetTokenCount( cDelim );
sal_uInt16 nIndex = 0;
ByteString aThis = ACCESSDELIM(DEFSTYLE);
aThis += ByteString(GetFull(), osl_getThreadTextEncoding());
for ( sal_uInt16 nToken = 0; nToken < nTokenCount; ++nToken )
{
ByteString aPath = ByteString(rPfad, osl_getThreadTextEncoding()).GetToken( 0, cDelim, nIndex );
if ( aPath.Len() )
{
if (aPath.GetChar(aPath.Len()-1)== ACCESSDELIM(DEFSTYLE)[0])
aPath.Erase(aPath.Len()-1);
aPath += aThis;
DirEntry aEntry( String(aPath, osl_getThreadTextEncoding()));
if ( aEntry.ToAbs() &&
( ( !bWild && aEntry.Exists() ) || ( bWild && aEntry.First() ) ) )
{
(*this) = aEntry;
return sal_True;
}
}
}
return sal_False;
}
/*************************************************************************
|*
|* DirEntry::ImpToRel()
|*
|* Beschreibung
|* Ersterstellung MI 17.06.93
|* Letzte Aenderung MI 17.06.93
|*
*************************************************************************/
sal_Bool DirEntry::ImpToRel( String aCurStr )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
DirEntry aThis(*this);
aThis.ToAbs();
String aThisStr( aThis.GetFull( FSYS_STYLE_HPFS ) );
// #109512 preserve case of path even if caseinsensitive
String aThisCompareStr( aThisStr ), aCurCompareStr( aCurStr );
if ( ! IsCaseSensitive() )
{
aThisCompareStr.ToLowerAscii();
aCurCompareStr.ToLowerAscii();
}
// "Ubereinstimmung pr"ufen
sal_uInt16 nPos = aThisCompareStr.Match( aCurCompareStr );
if ( nPos == STRING_MATCH && aThisStr.Len() != aCurStr.Len() )
nPos = Min( aThisStr.Len(), aCurStr.Len() );
// Sonderfall, die DirEntries sind identisch
if ( nPos == STRING_MATCH )
{
// dann ist der relative Pfad das aktuelle Verzeichnis
*this = DirEntry();
return sal_True;
}
// Sonderfall, die DirEntries sind total verschieden
if ( nPos == 0 )
{
// dann ist der relativste Pfad absolut
*this = aThis;
return sal_False;
}
// sonst nehmen wir die identischen Einzelteile vorne weg
while ( nPos > 0 && aThisStr.GetChar(nPos) != '\\' )
--nPos;
aThisStr.Erase( 0, nPos + ( ( aThisStr.GetChar(nPos) == '\\' ) ? 1 : 0 ) );
aCurStr.Erase( 0, nPos + ( ( aCurStr.GetChar(nPos) == '\\' ) ? 1 : 0 ) );
// und fuellen mit dem Level der Directories auf
for ( nPos = 0; nPos < aCurStr.Len(); ++nPos )
if ( aCurStr.GetChar(nPos) == '\\' )
aThisStr.Insert( String( "..\\", osl_getThreadTextEncoding() ), 0 );
// das ist dann unser relativer Pfad
*this = DirEntry( aThisStr, FSYS_STYLE_HPFS );
return sal_True;
}
/*************************************************************************
|*
|* DirEntry::CutRelParents()
|*
|* Beschreibung
|* Ersterstellung MI 01.08.95
|* Letzte Aenderung MI 01.08.95
|*
*************************************************************************/
sal_uInt16 DirEntry::CutRelParents()
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
// erstes '..' finden
DirEntry *pDir = 0;
DirEntry *pPar;
for ( pPar = this;
pPar && pPar->eFlag != FSYS_FLAG_PARENT;
pPar = pPar->pParent )
pDir = pPar;
// '..' zaehlen
sal_uInt16 nParCount = 0;
while ( pPar && pPar->eFlag == FSYS_FLAG_PARENT )
{
++nParCount;
pPar = pPar->pParent;
}
// cutten
if ( pDir )
DELETEZ(pDir->pParent);
else
eFlag = FSYS_FLAG_CURRENT;
return nParCount;
}
/*************************************************************************
|*
|* DirEntry::ToRel()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.06.93
|* Letzte Aenderung MI 17.06.93
|*
*************************************************************************/
sal_Bool DirEntry::ToRel()
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
DirEntry aCur;
aCur.ToAbs();
return ImpToRel( aCur.GetFull( FSYS_STYLE_HPFS ) );
}
/*************************************************************************
|*
|* DirEntry::ToRel()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
sal_Bool DirEntry::ToRel( const DirEntry& rStart )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
DirEntry aStart( rStart );
aStart.ToAbs();
return ImpToRel( aStart.GetFull( FSYS_STYLE_HPFS ) );
}
/*************************************************************************
|*
|* DirEntry::GetDevice()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
#ifndef UNX
DirEntry DirEntry::GetDevice() const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
const DirEntry *pTop = ImpGetTopPtr();
if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT || pTop->eFlag == FSYS_FLAG_RELROOT ) &&
pTop->aName.Len() )
return DirEntry( pTop->aName, FSYS_FLAG_VOLUME, FSYS_STYLE_HOST );
else
return DirEntry( ByteString(), FSYS_FLAG_INVALID, FSYS_STYLE_HOST );
}
#endif
/*************************************************************************
|*
|* DirEntry::SetBase()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 23.10.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
void DirEntry::SetBase( const String& rBase, char cSep )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
const char *p0 = ( aName.GetBuffer() );
const char *p1 = p0 + aName.Len() - 1;
while ( p1 >= p0 && *p1 != cSep )
p1--;
if ( p1 >= p0 )
{
// es wurde ein cSep an der Position p1 gefunden
aName.Erase( 0, static_cast< xub_StrLen >(p1 - p0) );
aName.Insert( ByteString(rBase, osl_getThreadTextEncoding()), 0 );
}
else
aName = ByteString(rBase, osl_getThreadTextEncoding());
}
/*************************************************************************
|*
|* DirEntry::GetSearchDelimiter()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 10.06.93
|* Letzte Aenderung MI 10.06.93
|*
*************************************************************************/
String DirEntry::GetSearchDelimiter( FSysPathStyle eFormatter )
{
return String( ByteString(SEARCHDELIM( GetStyle( eFormatter ) ) ), osl_getThreadTextEncoding());
}
/*************************************************************************
|*
|* DirEntry::GetMaxNameLen()
|*
|* Beschreibung Liefert die maximale Anzahl von Zeichen in
|* einzelnen Namensteile. Bei FileSystmen mit
|* fester Extension (FAT) zaehlt diese nicht mit.
|* Bei unbekannten FileSytemen und FSYS_STYLE_URL
|* wird USHRT_MAX zurueckgegeben.
|* Ersterstellung MI 17.06.97
|* Letzte Aenderung MI 17.06.97
|*
*************************************************************************/
sal_uInt16 DirEntry::GetMaxNameLen( FSysPathStyle eFormatter )
{
eFormatter = GetStyle( eFormatter );
switch ( eFormatter )
{
case FSYS_STYLE_MAC: return 31;
case FSYS_STYLE_FAT: return 8;
case FSYS_STYLE_VFAT:
case FSYS_STYLE_NTFS:
case FSYS_STYLE_NWFS:
case FSYS_STYLE_HPFS: return 255;
case FSYS_STYLE_SYSV: return 14;
case FSYS_STYLE_BSD: return 250;
default:
return USHRT_MAX;
}
}
/*************************************************************************
|*
|* DirEntry::TempName()
|*
|* Beschreibung FSYS.SDW - Aha, wo?
|* Ersterstellung VB 06.09.93 (im SWG)
|* Letzte Aenderung MI 06.02.98
|*
*************************************************************************/
namespace { struct TempNameBase_Impl : public rtl::Static< DirEntry, TempNameBase_Impl > {}; }
const DirEntry& DirEntry::SetTempNameBase( const String &rBase )
{
DirEntry aTempDir = DirEntry().TempName().GetPath();
aTempDir += DirEntry( rBase );
#ifdef UNX
ByteString aName( aTempDir.GetFull(), osl_getThreadTextEncoding());
if ( access( aName.GetBuffer(), W_OK | X_OK | R_OK ) )
{
// Create the directory and only on success give all rights to
// everyone. Use mkdir instead of DirEntry::MakeDir because
// this returns sal_True even if directory already exists.
if ( !mkdir( aName.GetBuffer(), S_IRWXU | S_IRWXG | S_IRWXO ) )
chmod( aName.GetBuffer(), S_IRWXU | S_IRWXG | S_IRWXO );
// This will not create a directory but perhaps FileStat called
// there modifies the DirEntry
aTempDir.MakeDir();
}
#else
aTempDir.MakeDir();
#endif
DirEntry &rEntry = TempNameBase_Impl::get();
rEntry = aTempDir.TempName( FSYS_KIND_DIR );
return rEntry;
}
DirEntry DirEntry::TempName( DirEntryKind eKind ) const
{
// ggf. Base-Temp-Dir verwenden (macht Remote keinen Sinn => vorher)
const DirEntry &rEntry = TempNameBase_Impl::get();
if ( !pParent && FSYS_FLAG_CURRENT != rEntry.eFlag && FSYS_FLAG_ABSROOT != eFlag )
{
DirEntry aFactory( rEntry );
aFactory += GetName();
return aFactory.TempName();
}
ByteString aDirName; // hiermit hatte MPW C++ Probleme - immmer noch??
char *ret_val;
size_t i;
// dertermine Directory, Prefix and Extension
char pfx[6];
char ext[5];
const char *dir;
const char *pWild = strchr( aName.GetBuffer(), '*' );
if ( !pWild )
pWild = strchr( aName.GetBuffer(), '?' );
if ( pWild )
{
if ( pParent )
aDirName = ByteString(pParent->GetFull(), osl_getThreadTextEncoding());
strncpy( pfx, aName.GetBuffer(), Min( (int)5, (int)(pWild-aName.GetBuffer()) ) );
pfx[ pWild-aName.GetBuffer() ] = 0;
const char *pExt = strchr( pWild, '.' );
if ( pExt )
{
strncpy( ext, pExt, 4 );
ext[4] = 0;
}
else
strcpy( ext, ".tmp" );
}
else
{
aDirName = ByteString(GetFull(), osl_getThreadTextEncoding());
strcpy( pfx, "sv" );
strcpy( ext, ".tmp" );
}
dir = aDirName.GetBuffer();
// wurde kein Dir angegeben, dann nehmen wir ein passendes TEMP-Verz.
char sBuf[_MAX_PATH];
if ( eFlag == FSYS_FLAG_CURRENT || ( !pParent && pWild ) )
dir = TempDirImpl(sBuf);
// ab hier leicht modifizierter Code von VB
DirEntry aRet(FSYS_FLAG_INVALID);
i = strlen(dir);
// need to add ?\\? + prefix + number + pid + .ext + '\0'
# define TMPNAME_SIZE ( 1 + 5 + 5 + 10 + 4 + 1 )
ret_val = new char[i + TMPNAME_SIZE ];
if (ret_val)
{
strcpy(ret_val,dir);
/* Make sure directory ends with a separator */
#if defined(WNT) || defined(OS2)
if ( i>0 && ret_val[i-1] != '\\' && ret_val[i-1] != '/' &&
ret_val[i-1] != ':')
ret_val[i++] = '\\';
#elif defined UNX
if (i>0 && ret_val[i-1] != '/')
ret_val[i++] = '/';
#else
#error unknown operating system
#endif
strncpy(ret_val + i, pfx, 5);
ret_val[i + 5] = '\0'; /* strncpy doesn't put a 0 if more */
i = strlen(ret_val); /* than 'n' chars. */
/* Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576
* Welcome to the 21st century, we can have longer filenames now ;)
* New format: pfx + "5 char milli/micro second res" + "current pid" + ".tmp"
*/
#if (defined MSC || defined __MINGW32__) && defined WNT
/* Milliseconds !! */
static unsigned long u = GetTickCount();
unsigned long mypid = static_cast<unsigned long>(_getpid());
#else
/* Microseconds !! */
static unsigned long u = clock();
unsigned long mypid = static_cast<unsigned long>(getpid());
#endif
for ( unsigned long nOld = u; ++u != nOld; ) /* Hae??? */
{
u %= 100000; /* on *NIX repeats every 100ms, maybe less if CLOCKS_PER_SEC > 10^6 */
snprintf(ret_val+i, TMPNAME_SIZE, "%05lu%lu", u, mypid);
strcat(ret_val,ext);
if ( FSYS_KIND_FILE == eKind )
{
SvFileStream aStream( String( ret_val, osl_getThreadTextEncoding()),
STREAM_WRITE|STREAM_SHARE_DENYALL );
if ( aStream.IsOpen() )
{
aStream.Seek( STREAM_SEEK_TO_END );
if ( 0 == aStream.Tell() )
{
aRet = DirEntry( String( ret_val, osl_getThreadTextEncoding()));
break;
}
aStream.Close();
}
}
else
{
// Redirect
String aRetVal(ret_val, osl_getThreadTextEncoding());
String aRedirected (aRetVal);
#ifndef BOOTSTRAP
FSysRedirector::DoRedirect( aRedirected );
#endif
if ( FSYS_KIND_DIR == eKind )
{
if ( 0 == _mkdir( ByteString(aRedirected.GetBuffer(), osl_getThreadTextEncoding()).GetBuffer() ) )
{
aRet = DirEntry( aRetVal );
break;
}
}
else
{
#if defined(UNX) || defined(OS2)
if( access( ByteString(aRedirected, osl_getThreadTextEncoding()).GetBuffer(), F_OK ) )
{
aRet = DirEntry( aRetVal );
break;
}
#else
struct stat aStat;
if ( stat( ByteString(aRedirected, osl_getThreadTextEncoding()).GetBuffer(), &aStat ) )
{
aRet = DirEntry( aRetVal );
break;
}
#endif
}
}
}
delete[] ret_val;
ret_val = 0;
}
return aRet;
}
/*************************************************************************
|*
|* DirEntry::operator[]()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 03.03.92
|* Letzte Aenderung MI 03.03.92
|*
*************************************************************************/
const DirEntry &DirEntry::operator[]( sal_uInt16 nParentLevel ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
//TPF: maybe to be implemented (FastFSys)
const DirEntry *pRes = this;
while ( pRes && nParentLevel-- )
pRes = pRes->pParent;
return *pRes;
}
/*************************************************************************
|*
|* DirEntry::ImpParseUnixName()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MI 26.05.93
|*
*************************************************************************/
FSysError DirEntry::ImpParseUnixName( const ByteString& rPfad, FSysPathStyle eStyle )
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
// die einzelnen Namen auf einen Stack packen
DirEntryStack aStack;
ByteString aPfad( rPfad );
do
{
// den Namen vor dem ersten "/" abspalten,
// falls '/' am Anfang, ist der Name '/',
// der Rest immer ohne die fuehrenden '/'.
// den ersten '/' suchen
sal_uInt16 nPos;
for ( nPos = 0;
nPos < aPfad.Len() && aPfad.GetChar(nPos) != '/';
nPos++ )
/* do nothing */;
// ist der Name die Root des aktuellen Drives?
if ( nPos == 0 && aPfad.Len() > 0 && ( aPfad.GetChar(0) == '/' ) )
{
// Root-Directory des aktuellen Drives
aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) );
}
else
{
// den Namen ohne Trenner abspalten
aName = aPfad.Copy( 0, nPos );
// stellt der Name die aktuelle Directory dar?
if ( aName == "." )
/* do nothing */;
#ifdef UNX
// stellt der Name das User-Dir dar?
else if ( aName == "~" )
{
DirEntry aHome( String( (const char *) getenv( "HOME" ), osl_getThreadTextEncoding()) );
for ( sal_uInt16 n = aHome.Level(); n; --n )
aStack.Push( new DirEntry( aHome[ (sal_uInt16) n-1 ] ) );
}
#endif
// stellt der Name die Parent-Directory dar?
else if ( aName == ".." )
{
// ist nichts, ein Parent oder eine relative Root
// auf dem Stack?
if ( ( aStack.Count() == 0 ) ||
( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) )
// fuehrende Parents kommen auf den Stack
aStack.Push( new DirEntry( ByteString(), FSYS_FLAG_PARENT, eStyle ) );
// ist es eine absolute Root
else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT ) {
// die hat keine Parent-Directory
return FSYS_ERR_NOTEXISTS;
}
else
// sonst hebt der Parent den TOS auf
delete aStack.Pop();
}
else
{
DirEntry *pNew = NULL;
// normalen Entries kommen auf den Stack
pNew = new DirEntry( aName, FSYS_FLAG_NORMAL, eStyle );
if ( !pNew->IsValid() )
{
aName = rPfad;
ErrCode eErr = pNew->GetError();
delete pNew;
return eErr;
}
aStack.Push( pNew );
}
}
// den Restpfad bestimmen
aPfad.Erase( 0, nPos + 1 );
while ( aPfad.Len() && ( aPfad.GetChar(0) == '/' ) )
aPfad.Erase( 0, 1 );
}
while ( aPfad.Len() );
// Haupt-Entry (selbst) zuweisen
if ( aStack.Count() == 0 )
{
eFlag = FSYS_FLAG_CURRENT;
aName.Erase();
}
else
{
eFlag = aStack.Top()->eFlag;
aName = aStack.Top()->aName;
delete aStack.Pop();
}
// die Parent-Entries vom Stack holen
DirEntry** pTemp = &pParent;
while ( aStack.Count() )
{
*pTemp = aStack.Pop();
pTemp = &( (*pTemp)->pParent );
}
return FSYS_ERR_OK;
}
/*************************************************************************
|*
|* DirEntry::MakeShortName()
|*
|* Beschreibung
|* Ersterstellung TLX
|* Letzte Aenderung PB 21.08.97 (in CreateEntry_Impl())
|*
*************************************************************************/
ErrCode CreateEntry_Impl( const DirEntry &rPath, DirEntryKind eKind )
{
// versuchen, anzulegen (ausser bei FSYS_KIND_ALL)
ErrCode eErr = ERRCODE_NONE;
if ( FSYS_KIND_FILE == eKind )
{
SvFileStream aStream( rPath.GetFull(), STREAM_STD_WRITE );
aStream.WriteLine( "" );
eErr = aStream.GetError();
}
else if ( FSYS_KIND_ALL != eKind )
eErr = rPath.MakeDir() ? ERRCODE_NONE : ERRCODE_IO_UNKNOWN;
// erfolgreich?
if ( !rPath.Exists() )
eErr = ERRCODE_IO_UNKNOWN; // Doch was schiefgegangen ?
// ggf. wieder l"oschen
if ( FSYS_KIND_NONE == eKind )
rPath.Kill();
// Fehlercode zur?ckliefern
return eErr;
}
sal_Bool IsValidEntry_Impl( const DirEntry &rPath,
const String &rLongName,
DirEntryKind eKind,
sal_Bool bIsShortened,
sal_Bool bUseDelim )
{
// Parameter-Pr"uefung
DBG_ASSERT( eKind == FSYS_KIND_NONE || eKind == FSYS_KIND_ALL ||
eKind == FSYS_KIND_FILE || eKind == FSYS_KIND_DIR,
"invalid entry-kind" );
// Alle von MSDOS erreichbaren FSYS_STYLES muessen den
// MSDOS Filenamenanforderungen genuegen. Sonst wird probiert,
// ob sich eine Datei des gewuenschten Names anlegen laesst.
FSysPathStyle eStyle = DirEntry::GetPathStyle( rPath.GetDevice().GetName() );
DirEntry aPath(rPath);
DirEntry aName(rLongName, eStyle);
if ( !aName.IsValid() || aName.Level() != 1 )
return sal_False;
aPath += aName;
if ( 1 == aPath.Level() )
return sal_False;
if ( eStyle == FSYS_STYLE_FAT || eStyle == FSYS_STYLE_NWFS ||
eStyle == FSYS_STYLE_UNKNOWN )
{
DirEntry aDosEntry( rLongName, FSYS_STYLE_FAT );
if ( !aDosEntry.IsValid() )
return sal_False;
}
// Pfad-Trenner sind nicht erlaubt (bei ungek"urzten auch nicht FSYS_SHORTNAME_DELIMITER)
char cDelim = bUseDelim == 2 ? FSYS_SHORTNAME_DELIMITER : char(0);
if (
rLongName.Search(DirEntry::GetAccessDelimiter()) != STRING_NOTFOUND ||
(!bIsShortened && rLongName.Search(cDelim) != STRING_NOTFOUND)
)
{
return sal_False;
}
// MI: Abfrage nach 'CON:' etc. wird jetzt in Exists() mitgemacht
if ( aPath.Exists() )
return sal_False;
return (ERRCODE_NONE == CreateEntry_Impl( aPath, eKind ));
}
//-------------------------------------------------------------------------
#define MAX_EXT_FAT 3
#define MAX_LEN_FAT 8
#define INVALID_CHARS_FAT "\\/\"':|^<>[]?* "
#define MAX_EXT_MAC 16 // nur wegen sinnvoller Namensk"rzung
#define MAX_LEN_MAC 31
#define INVALID_CHARS_MAC "\":"
#define MAX_EXT_MAX 250
#define MAX_LEN_MAX 255
#define INVALID_CHARS_DEF "\\/\"':|^<>?*"
sal_Bool DirEntry::MakeShortName( const String& rLongName, DirEntryKind eKind,
sal_Bool bUseDelim, FSysPathStyle eStyle )
{
String aLongName(rLongName);
// Alle '#' aus den Dateinamen entfernen, weil das INetURLObject
// damit Probleme hat. Siehe auch #51246#
aLongName.EraseAllChars( '#' );
ByteString bLongName(aLongName, osl_getThreadTextEncoding());
// Auf Novell-Servern (wegen der rottigen Clients) nur 7bit ASCII
// HRO: #69627# Weg mit dem Scheiss. Wenn es Client gibt, die so einen
// BUG haben, dann muss halt der Client ersetzt werden, aber doch nicht das
// Office kastrieren !!!
#if 0
if ( FSYS_STYLE_NWFS == GetPathStyle( ImpGetTopPtr()->GetName() ) )
{
for ( sal_uInt16 n = aLongName.Len(); n; --n )
{
short nChar = aLongName(n-1);
if ( nChar < 32 || nChar >= 127 )
aLongName.Erase( n-1, 1 );
}
}
#endif
// bei FSYS_KIND_ALL den alten Namen merken und abh"angen (rename)
ByteString aOldName;
if ( FSYS_KIND_ALL == eKind )
{
aOldName = ByteString(CutName(), osl_getThreadTextEncoding());
aOldName = CMP_LOWER(aOldName);
}
// ist der Langname direkt verwendbar?
if ( IsValidEntry_Impl( *this, aLongName, eKind, sal_False, bUseDelim ) )
{
operator+=( DirEntry(aLongName) );
return sal_True;
}
// max L"angen feststellen
sal_uInt16 nMaxExt, nMaxLen;
if ( FSYS_STYLE_DETECT == eStyle )
eStyle = DirEntry::GetPathStyle( GetDevice().GetName() );
ByteString aInvalidChars;
switch ( eStyle )
{
case FSYS_STYLE_FAT:
nMaxExt = MAX_EXT_FAT;
nMaxLen = MAX_LEN_FAT;
aInvalidChars = INVALID_CHARS_FAT;
break;
case FSYS_STYLE_MAC:
nMaxExt = MAX_EXT_MAC;
nMaxLen = MAX_LEN_MAC;
aInvalidChars = INVALID_CHARS_MAC;
break;
default:
nMaxExt = MAX_EXT_MAX;
nMaxLen = MAX_LEN_MAX;
aInvalidChars = INVALID_CHARS_DEF;
}
// Extension abschneiden und kuerzen
ByteString aExt;
ByteString aFName = bLongName;
if ( FSYS_STYLE_MAC != eStyle )
{
DirEntry aUnparsed;
aUnparsed.aName = bLongName;
aExt = ByteString(aUnparsed.CutExtension(), osl_getThreadTextEncoding());
aFName = aUnparsed.aName;
if ( aExt.Len() > nMaxExt )
{
char c = aExt.GetChar( aExt.Len() - 1 );
aExt.Erase(nMaxExt-1);
aExt += c;
}
}
if ( FSYS_STYLE_FAT != eStyle )
{
// ausser auf einem FAT-System geh"ort die Extension zur
// Maxl"ange. Muss also vorher mit dem Punkt abgezogen werden.
nMaxLen -= ( aExt.Len() + 1 );
}
// Name k"urzen
ByteString aSName;
for ( const char *pc = aFName.GetBuffer(); aSName.Len() < nMaxLen && *pc; ++pc )
{
if ( STRING_NOTFOUND == aInvalidChars.Search( *pc ) &&
(unsigned char) *pc >= (unsigned char) 32 &&
( !aSName.Len() || *pc != ' ' || aSName.GetChar(aSName.Len()-1) != ' ' ) )
aSName += *pc;
}
aSName.EraseTrailingChars();
// HRO: #74246# Also cut leading spaces
aSName.EraseLeadingChars();
if ( !aSName.Len() )
aSName = "noname";
// kommt dabei der alte Name raus?
ByteString aNewName = aSName;
if ( aExt.Len() )
( aNewName += '.' ) += aExt;
operator+=( DirEntry(String(aNewName, osl_getThreadTextEncoding())) );
if ( FSYS_KIND_ALL == eKind && CMP_LOWER(aName) == aOldName )
if ( FSYS_KIND_ALL == eKind && CMP_LOWER(ByteString(GetName(), osl_getThreadTextEncoding())) == aOldName )
return sal_True;
// kann der gek"urzte Name direkt verwendet werden?
if ( !Exists() && (ERRCODE_NONE == CreateEntry_Impl( *this, eKind )) )
return sal_True;
// darf '?##' verwendet werden, um eindeutigen Name zu erzeugen?
if ( bUseDelim )
{
// eindeutigen Namen per '?##' erzeugen
aSName.Erase( nMaxLen-3 );
if ( bUseDelim != 2 )
aSName += FSYS_SHORTNAME_DELIMITER;
for ( int n = 1; n < 99; ++n )
{
// Name zusammensetzen
ByteString aTmpStr( aSName );
aTmpStr += ByteString::CreateFromInt32(n);
if ( aExt.Len() )
( aTmpStr += '.' ) += aExt;
// noch nicht vorhanden?
SetName( String(aTmpStr, osl_getThreadTextEncoding()) );
if ( !Exists() )
{
// Fehler setzen !!!
nError = CreateEntry_Impl( *this, eKind );
return (ERRCODE_NONE == nError);
}
}
}
// keine ## mehr frei / ?## soll nicht verwendet werden
nError = ERRCODE_IO_ALREADYEXISTS;
return sal_False;
}
/*************************************************************************
|*
|* DirEntry::CreatePath()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MA 02.12.91
|*
*************************************************************************/
sal_Bool DirEntry::MakeDir( sal_Bool bSloppy ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
// Schnellpruefung, ob vorhanden
if ( FileStat( *this ).IsKind( FSYS_KIND_DIR ) )
return sal_True;
if ( bSloppy && pParent )
if ( FileStat( *pParent ).IsKind( FSYS_KIND_DIR ) )
return sal_True;
const DirEntry *pNewDir = bSloppy ? pParent : this;
if ( pNewDir )
{
// den Path zum Dir erzeugen
if ( pNewDir->pParent && !pNewDir->pParent->MakeDir(sal_False) )
return sal_False;
// das Dir selbst erzeugen
if ( pNewDir->eFlag == FSYS_FLAG_ABSROOT ||
pNewDir->eFlag == FSYS_FLAG_ABSROOT ||
pNewDir->eFlag == FSYS_FLAG_VOLUME )
return sal_True;
else
{
//? nError = ???
if ( FileStat( *pNewDir ).IsKind( FSYS_KIND_DIR ) )
return sal_True;
else
{
FSysFailOnErrorImpl();
String aDirName(pNewDir->GetFull());
#ifndef BOOTSTRAP
FSysRedirector::DoRedirect( aDirName );
#endif
ByteString bDirName( aDirName, osl_getThreadTextEncoding() );
bDirName = GUI2FSYS( bDirName );
#ifdef WIN32
SetLastError(0);
#endif
sal_Bool bResult = (0 == _mkdir( (char*) bDirName.GetBuffer() ));
if ( !bResult )
{
// Wer hat diese Methode const gemacht ?
#ifdef WIN32
((DirEntry *)this)->SetError( Sys2SolarError_Impl( GetLastError() ) );
#else
((DirEntry *)this)->SetError( Sys2SolarError_Impl( errno ) );
#endif
}
return bResult;
}
}
}
return sal_True;
}
/*************************************************************************
|*
|* DirEntry::CopyTo()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MI 07.08.96
|*
*************************************************************************/
FSysError DirEntry::CopyTo( const DirEntry& rDest, FSysAction nActions ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
if ( FSYS_ACTION_COPYFILE != (nActions & FSYS_ACTION_COPYFILE) )
#ifdef UNX
{
// Hardlink anlegen
HACK(redirection missing)
ByteString aThis(GUI2FSYS(GetFull()), osl_getThreadTextEncoding());
ByteString aDest(GUI2FSYS(rDest.GetFull()), osl_getThreadTextEncoding());
if (link( aThis.GetBuffer(), aDest.GetBuffer() ) == -1)
return Sys2SolarError_Impl( errno );
else
return FSYS_ERR_OK;
}
#else
return FSYS_ERR_NOTSUPPORTED;
#endif
FileCopier fc(*this, rDest);
return fc.Execute(nActions);
}
/*************************************************************************
|*
|* DirEntry::MoveTo()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung HRO 24.03.99
|*
*************************************************************************/
#if defined WNT || defined UNX || defined OS2
FSysError DirEntry::MoveTo( const DirEntry& rNewName ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
/*
FileStat aSourceStat(*this);
if ( !aSourceStat.IsKind(FSYS_KIND_FILE) )
return FSYS_ERR_NOTAFILE;
*/
DirEntry aDest(rNewName);
FileStat aDestStat(rNewName);
if ( aDestStat.IsKind(FSYS_KIND_DIR ) )
{
aDest += String(aName, osl_getThreadTextEncoding());
}
if ( aDest.Exists() )
{
return FSYS_ERR_ALREADYEXISTS;
}
#if defined(OS2)
if ( FileStat(*this).IsKind(FSYS_KIND_DIR) && aDest.GetPath() != GetPath() )
{
return FSYS_ERR_NOTSUPPORTED;
}
#endif
FSysFailOnErrorImpl();
String aFrom( GetFull() );
#ifndef BOOTSTRAP
FSysRedirector::DoRedirect(aFrom);
#endif
String aTo( aDest.GetFull() );
#ifndef BOOTSTRAP
FSysRedirector::DoRedirect(aTo);
#endif
ByteString bFrom(aFrom, osl_getThreadTextEncoding());
ByteString bTo(aTo, osl_getThreadTextEncoding());
bFrom = GUI2FSYS(bFrom);
bTo = GUI2FSYS(bTo);
#ifdef WNT
// MoveTo nun atomar
SetLastError(0);
DirEntry aFromDevice(String(bFrom, osl_getThreadTextEncoding()));
DirEntry aToDevice(String(bTo,osl_getThreadTextEncoding()));
aFromDevice.ToAbs();
aToDevice.ToAbs();
aFromDevice=aFromDevice.GetDevice();
aToDevice=aToDevice.GetDevice();
//Quelle und Ziel auf gleichem device?
if (aFromDevice==aToDevice)
{
// ja, also intra-device-move mit MoveFile
MoveFile( bFrom.GetBuffer(), bTo.GetBuffer() );
// MoveFile ist buggy bei cross-device operationen.
// Der R?ckgabewert ist auch dann sal_True, wenn nur ein Teil der Operation geklappt hat.
// Zudem zeigt MoveFile unterschiedliches Verhalten bei unterschiedlichen NT-Versionen.
return Sys2SolarError_Impl( GetLastError() );
}
else
{
//nein, also inter-device-move mit copy/delete
FSysError nCopyError = CopyTo(rNewName, FSYS_ACTION_COPYFILE);
DirEntry aKill(String(bTo, osl_getThreadTextEncoding()));
FileStat aKillStat(String(bTo, osl_getThreadTextEncoding()));
if ( aKillStat.IsKind(FSYS_KIND_DIR ) )
{
aKill += String(aName, osl_getThreadTextEncoding());
}
if (nCopyError==FSYS_ERR_OK)
{
if (Kill()==FSYS_ERR_OK)
{
return FSYS_ERR_OK;
}
else
{
aKill.Kill();
return FSYS_ERR_ACCESSDENIED;
}
}
else
{
aKill.Kill();
return nCopyError;
}
}
#else
// #68639#
// on some nfs connections rename with from == to
// leads to destruction of file
if ( ( aFrom != aTo ) && ( 0 != rename( bFrom.GetBuffer(), bTo.GetBuffer() ) ) )
#if !defined(UNX) && !defined(OS2)
return Sys2SolarError_Impl( GetLastError() );
#else
{
if( errno == EXDEV )
// cross device geht latuernich nicht mit rename
{
FILE *fpIN = fopen( bFrom.GetBuffer(), "r" );
FILE *fpOUT = fopen( bTo.GetBuffer(), "w" );
if( fpIN && fpOUT )
{
char pBuf[ 16384 ];
int nBytes, nWritten, nErr = 0;
errno = 0;
while( ( nBytes = fread( pBuf, 1, sizeof(pBuf), fpIN ) ) && ! nErr )
{
nWritten = fwrite( pBuf, 1, nBytes, fpOUT );
// Fehler im fwrite ?
if( nWritten < nBytes )
{
nErr = errno;
break;
}
}
fclose( fpIN );
fclose( fpOUT );
if ( nErr )
{
unlink( bTo.GetBuffer() );
return Sys2SolarError_Impl( nErr );
}
else
{
unlink( bFrom.GetBuffer() );
}
}
else
{
return Sys2SolarError_Impl( EXDEV );
}
}
else
{
return Sys2SolarError_Impl( errno );
}
}
#endif
#endif
return ERRCODE_NONE;
}
#endif
/*************************************************************************
|*
|* DirEntry::Kill()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 26.04.91
|* Letzte Aenderung MI 07.08.96
|*
*************************************************************************/
FSysError DirEntry::Kill( FSysAction nActions ) const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
FSysError eError = FSYS_ERR_OK;
FSysFailOnErrorImpl();
// Name als doppelt 0-terminierter String
String aTmpName( GetFull() );
#ifndef BOOTSTRAP
FSysRedirector::DoRedirect( aTmpName );
#endif
ByteString bTmpName( aTmpName, osl_getThreadTextEncoding());
bTmpName = GUI2FSYS(bTmpName);
char *pName = new char[bTmpName.Len()+2];
strcpy( pName, bTmpName.GetBuffer() );
pName[bTmpName.Len()+1] = (char) 0;
//read-only files sollen auch geloescht werden koennen
sal_Bool isReadOnly = FileStat::GetReadOnlyFlag(*this);
if (isReadOnly)
{
FileStat::SetReadOnlyFlag(*this, sal_False);
}
// directory?
if ( FileStat( *this ).IsKind(FSYS_KIND_DIR) )
{
// Inhalte recursiv loeschen?
if ( FSYS_ACTION_RECURSIVE == (nActions & FSYS_ACTION_RECURSIVE) )
{
Dir aDir( *this, FSYS_KIND_DIR|FSYS_KIND_FILE );
for ( sal_uInt16 n = 0; eError == FSYS_ERR_OK && n < aDir.Count(); ++n )
{
const DirEntry &rSubDir = aDir[n];
DirEntryFlag flag = rSubDir.GetFlag();
if ( flag != FSYS_FLAG_CURRENT && flag != FSYS_FLAG_PARENT )
eError = rSubDir.Kill(nActions);
}
}
// das Dir selbst loeschen
#ifdef WIN32
SetLastError(0);
#endif
if ( eError == FSYS_ERR_OK && 0 != _rmdir( (char*) pName ) )
//
{
// falls L"oschen nicht ging, CWD umsetzen
#ifdef WIN32
eError = Sys2SolarError_Impl( GetLastError() );
#else
eError = Sys2SolarError_Impl( errno );
#endif
if ( eError )
{
GetPath().SetCWD();
#ifdef WIN32
SetLastError(0);
#endif
if (_rmdir( (char*) pName) != 0)
{
#ifdef WIN32
eError = Sys2SolarError_Impl( GetLastError() );
#else
eError = Sys2SolarError_Impl( errno );
#endif
}
else
{
eError = FSYS_ERR_OK;
}
}
}
}
else
{
if ( FSYS_ACTION_USERECYCLEBIN == (nActions & FSYS_ACTION_USERECYCLEBIN) )
{
#ifdef OS2
eError = ApiRet2ToSolarError_Impl( DosDelete( (PSZ) pName ) );
#elif defined(WNT)
SHFILEOPSTRUCT aOp;
aOp.hwnd = 0;
aOp.wFunc = FO_DELETE;
aOp.pFrom = pName;
aOp.pTo = 0;
aOp.fFlags = FOF_ALLOWUNDO|FOF_SILENT|FOF_NOCONFIRMATION;
aOp.hNameMappings = 0;
aOp.lpszProgressTitle = 0;
eError = Sys2SolarError_Impl( SHFileOperation( &aOp ) );
#else
eError = ERRCODE_IO_NOTSUPPORTED;
#endif
}
else
{
#ifdef WIN32
SetLastError(0);
#endif
if ( 0 != _unlink( (char*) pName ) )
{
#ifdef WIN32
eError = Sys2SolarError_Impl( GetLastError() );
#else
eError = Sys2SolarError_Impl( errno );
#endif
}
else
{
eError = ERRCODE_NONE;
}
}
}
//falls Fehler, originales read-only flag wieder herstellen
if ( isReadOnly && (eError!=ERRCODE_NONE) )
{
FileStat::SetReadOnlyFlag(*this, isReadOnly);
}
delete[] pName;
return eError;
}
/*************************************************************************
|*
|* DirEntry::Contains()
|*
|* Beschreibung ob rSubEntry direkt oder indirect in *this liegt
|* Ersterstellung MI 20.03.97
|* Letzte Aenderung MI 20.03.97
|*
*************************************************************************/
sal_Bool DirEntry::Contains( const DirEntry &rSubEntry ) const
{
DBG_ASSERT( IsAbs() && rSubEntry.IsAbs(), "must be absolute entries" );
sal_uInt16 nThisLevel = Level();
sal_uInt16 nSubLevel = rSubEntry.Level();
if ( nThisLevel < nSubLevel )
{
for ( ; nThisLevel; --nThisLevel, --nSubLevel )
if ( (*this)[nThisLevel-1] != rSubEntry[nSubLevel-1] )
return sal_False;
return sal_True;
}
return sal_False;
}
/*************************************************************************
|*
|* DirEntry::Level()
|*
|* Beschreibung FSYS.SDW
|* Ersterstellung MI 03.03.92
|* Letzte Aenderung MI 03.03.92
|*
*************************************************************************/
sal_uInt16 DirEntry::Level() const
{
DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
sal_uInt16 nLevel = 0;
const DirEntry *pRes = this;
while ( pRes )
{
pRes = pRes->pParent;
nLevel++;
}
return nLevel;
}
/*************************************************************************
|*
|* DirEntry::ConvertNameToSystem()
|*
|* Beschreibung
|* Ersterstellung DV 29.03.96
|* Letzte Aenderung DV 29.03.96
|*
*************************************************************************/
String DirEntry::ConvertNameToSystem( const String &rName )
{
return rName;
}
/*************************************************************************
|*
|* DirEntry::ConvertSystemToName()
|*
|* Beschreibung
|* Ersterstellung DV 29.03.96
|* Letzte Aenderung DV 29.03.96
|*
*************************************************************************/
String DirEntry::ConvertSystemToName( const String &rName )
{
return rName;
}
/*************************************************************************
|*
|* DirEntry::IsValid()
|*
|* Beschreibung
|* Ersterstellung MI 18.09.93
|* Letzte Aenderung TPF 18.09.98
|*
*************************************************************************/
sal_Bool DirEntry::IsValid() const
{
return (nError == FSYS_ERR_OK);
}
/*************************************************************************
|*
|* DirEntry::IsRFSAvailable()
|*
|* Beschreibung
|* Ersterstellung TPF 21.10.98
|* Letzte Aenderung TPF 21.10.98
|*
*************************************************************************/
sal_Bool DirEntry::IsRFSAvailable()
{
return sal_False;
}
/*************************************************************************
|*
|* IsLongNameOnFAT()
|*
|* Beschreibung ?berpr?ft , ob das DirEntry einen langen
|* Filenamen auf einer FAT-Partition enth?lt (EAs).
|* (eigentlich nur f?r OS2 interessant)
|* Ersterstellung TPF 02.10.98
|* Letzte Aenderung TPF 01.03.1999
|*
*************************************************************************/
sal_Bool DirEntry::IsLongNameOnFAT() const
{
// FAT-System?
DirEntry aTempDirEntry(*this);
aTempDirEntry.ToAbs();
if (DirEntry::GetPathStyle(aTempDirEntry.GetDevice().GetName().GetChar(0)) != FSYS_STYLE_FAT)
{
return sal_False; // nein, also false
}
// DirEntry-Kette auf lange Dateinamen pr?fen
for( sal_uInt16 iLevel = this->Level(); iLevel > 0; iLevel-- )
{
const DirEntry& rEntry = (const DirEntry&) (*this)[iLevel-1];
String aBase( rEntry.GetBase() );
String aExtension( rEntry.GetExtension() );
if (aBase.Len()>8) // Name > 8?
{
return sal_True;
}
if (aExtension.Len()>3) // Extension > 3?
{
return sal_True;
}
}
return sal_False;
}
//========================================================================
#if defined(DBG_UTIL)
void FSysTest()
{
}
#endif