/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #if !defined UNX #ifdef WNT #include #undef GetObject #endif #include #include #endif #if defined(UNX) #include #include #include #endif #include #include #include #include #include #include #include "comdep.hxx" #include #define _TOOLS_HXX #include #include #ifdef UNX #define _MAX_PATH 260 #endif #include #include #include #include #include using namespace osl; using ::rtl::OUString; 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_FORMAT: return ERRCODE_IO_WRONGFORMAT; case ERROR_INVALID_ACCESS: return ERRCODE_IO_ACCESSDENIED; 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_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 } OSL_TRACE( "FSys: unknown system error %d occurred", nSysErr ); return FSYS_ERR_UNKNOWN; } class DirEntryStack { private: ::std::vector< DirEntry* > maStack; public: DirEntryStack() {}; ~DirEntryStack(); inline void Push( DirEntry *pEntry ); inline DirEntry* Pop(); inline DirEntry* Top(); inline DirEntry* Bottom(); inline bool Empty(); inline void Clear(); }; inline void DirEntryStack::Push( DirEntry *pEntry ) { maStack.push_back( pEntry ); } inline DirEntry* DirEntryStack::Pop() { DirEntry* pEntry = NULL; if ( !maStack.empty() ) { pEntry = maStack.back(); maStack.pop_back(); } return pEntry; } inline DirEntry* DirEntryStack::Top() { return maStack.empty() ? NULL : maStack.back(); } inline DirEntry* DirEntryStack::Bottom() { return maStack.empty() ? NULL : maStack.front(); } inline bool DirEntryStack::Empty() { return maStack.empty(); } inline void DirEntryStack::Clear() { maStack.clear(); } DBG_NAME( DirEntry ); DirEntryStack::~DirEntryStack() { maStack.clear(); } #ifdef DBG_UTIL /** Check DirEntry for DBG_UTIL @param p Pointer to DirEntry @return char* Error-TExtension or NULL */ const char* ImpCheckDirEntry( const void* p ) { DirEntry* p0 = (DirEntry*)p; if ( p0->pParent ) DBG_CHKOBJ( p0->pParent, DirEntry, ImpCheckDirEntry ); return NULL; } #endif /** Insert "..." for max length of nMaxChars */ rtl::OString ImplCutPath( const rtl::OString& rStr, sal_Int32 nMax, char cAccDel ) { sal_Int32 nMaxPathLen = nMax; sal_Bool bInsertPrefix = sal_False; sal_Int32 nBegin = rStr.indexOf(cAccDel); rtl::OStringBuffer aCutPath(rStr); if( nBegin == -1 ) nBegin = 0; else nMaxPathLen += 2; // Prefix : while( aCutPath.getLength() > nMaxPathLen ) { sal_Int32 nEnd = aCutPath.toString().indexOf(cAccDel, nBegin + 1); sal_Int32 nCount; if ( nEnd != -1 ) { nCount = nEnd - nBegin; aCutPath.remove(nBegin, nCount); bInsertPrefix = sal_True; } else break; } if ( aCutPath.getLength() > nMaxPathLen ) { for ( sal_Int32 n = nMaxPathLen; n > nMaxPathLen/2; --n ) { if (!comphelper::string::isalnumAscii(aCutPath[n])) { comphelper::string::truncateToLength(aCutPath, n); aCutPath.append(RTL_CONSTASCII_STRINGPARAM("...")); break; } } } if ( bInsertPrefix ) { rtl::OStringBuffer aIns; aIns.append(cAccDel).append(RTL_CONSTASCII_STRINGPARAM("...")); aCutPath.insert(nBegin, aIns.makeStringAndClear()); } return aCutPath.makeStringAndClear(); } FSysError DirEntry::ImpParseName( const rtl::OString& rPfad ) { #if defined(WNT) DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); // put single names onto stack String aPfad(rtl::OStringToOUString(rPfad, osl_getThreadTextEncoding())); DirEntryStack aStack; do { // split name before first "\\", // if '\\' is at beginning of string, name is set to '\\'. // ":" also splits the string and belongs to the name. // search first occurance of '\\', '/' or ':' sal_uInt16 nPos; for ( nPos = 0; nPos < aPfad.Len() && //?O aPfad.GetChar(nPos) != '\\' && aPfad.GetChar(nPos) != '/' && //?O aPfad.GetChar(nPos) != ':'; //?O nPos++ ) /* do nothing */; // is the name a 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 = rtl::OUStringToOString(aPfad.Copy( 2, nPos-2 ), osl_getThreadTextEncoding()); aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT ) ); } // Is the name the root of the current drive? else if ( nPos == 0 && aPfad.Len() > 0 && ( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) ) { // Push root directory of current drive aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) ); } else { // Is the name itself a drive? if ( nPos < aPfad.Len() && aPfad.GetChar(nPos) == ':' ) { aName = rtl::OUStringToOString(aPfad.Copy( 0, nPos + 1 ), osl_getThreadTextEncoding()); // Is the name the root of a drive? if ( (nPos + 1) < aPfad.Len() && ( aPfad.GetChar(nPos+1) == '\\' || aPfad.GetChar(nPos+1) == '/' ) ) { // unsupported if stack not empty or is a Novell format (URL) if ( !aStack.Empty() || aName.getLength() > 2 ) { aName = rPfad; return FSYS_ERR_MISPLACEDCHAR; } // Push as root directory of drive aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT ) ); } else { // clear stack if another drive is currently on it if ( !aStack.Empty() ) { rtl::OString aThis(aStack.Bottom()->aName); aThis = aThis.toAsciiLowerCase(); rtl::OString aOther(aName); aOther = aOther.toAsciiLowerCase(); if (aThis.compareTo(aOther) != 0) aStack.Clear(); } if ( aStack.Empty() ) aStack.Push( new DirEntry( aName, FSYS_FLAG_RELROOT ) ); } } // Name is not a drive else { // split the name without seperator aName = rtl::OUStringToOString(aPfad.Copy( 0, nPos ), osl_getThreadTextEncoding()); // Is the name the current directory? if ( aName == "." ) /* do nothing */; // Is the name the parent directory? else if ( aName == ".." ) { // Is the stack empty, or a parent (or relative root) on it? if ( ( aStack.Empty() ) || ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) || ( aStack.Top()->eFlag == FSYS_FLAG_RELROOT ) ) // add leading parent to stack aStack.Push( new DirEntry( FSYS_FLAG_PARENT ) ); // It's an absolute root path else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT ) { // Then there is no parent directory aName = rPfad; return FSYS_ERR_NOTEXISTS; } else // Otherwise removee parent TOS delete aStack.Pop(); } else { // add ordinary entries to the stack DirEntry *pNew = new DirEntry( aName, FSYS_FLAG_NORMAL ); if ( !pNew->IsValid() ) { aName = rPfad; ErrCode eErr = pNew->GetError(); delete pNew; return eErr; } aStack.Push( pNew ); } } } // determine remainder of path 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; // Set the main entry itself if ( aStack.Empty() ) { eFlag = FSYS_FLAG_CURRENT; aName = rtl::OString(); } else { eFlag = aStack.Top()->eFlag; aName = aStack.Top()->aName; nErr = aStack.Top()->nError; delete aStack.Pop(); } // pop parent entry from stack DirEntry** pTemp = &pParent; while ( !aStack.Empty() ) { *pTemp = aStack.Pop(); // set member pointer to the pParent of the member's own parent pTemp = &( (*pTemp)->pParent ); } // Does this describe a volume? if ( !pParent && eFlag == FSYS_FLAG_RELROOT && !aName.isEmpty() ) eFlag = FSYS_FLAG_VOLUME; // use full aName if error code was set if ( nErr ) aName = rPfad; return nErr; #else DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); // Add single names to the stack DirEntryStack aStack; rtl::OString aPfad(rPfad); do { // split names on the first occurance of "/", // if '/' starts the string, it itself becomes the name // search first occurance of "/" sal_uInt16 nPos; for ( nPos = 0; nPos < aPfad.getLength() && aPfad[nPos] != '/'; nPos++ ) /* do nothing */; // is the name the root of the current drive? if ( nPos == 0 && !aPfad.isEmpty() && ( aPfad[0] == '/' ) ) { // push root directory of current drive to stack aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) ); } else { // split name without seperator aName = aPfad.copy(0, nPos); // Is the name the current directory? if ( aName == "." ) /* do nothing */; #ifdef UNX // Is the name the user's home directory? 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 // Is the name the current parent directory? else if ( aName == ".." ) { // Is the stack empty, or a parent (or relative root) is on top? if ( ( aStack.Empty() ) || ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) ) { // push leading parents to stack aStack.Push( new DirEntry(rtl::OString(), FSYS_FLAG_PARENT) ); } // Is the name an absolute root? else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT ) { // they do not have parent directories return FSYS_ERR_NOTEXISTS; } else // otherwise remove parent TOS from stack delete aStack.Pop(); } else { DirEntry *pNew = NULL; // push ordinary entries on the stack pNew = new DirEntry( aName, FSYS_FLAG_NORMAL ); if ( !pNew->IsValid() ) { aName = rPfad; ErrCode eErr = pNew->GetError(); delete pNew; return eErr; } aStack.Push( pNew ); } } // get remainder of path aPfad = nPos < aPfad.getLength() ? aPfad.copy(nPos + 1) : rtl::OString(); while ( !aPfad.isEmpty() && ( aPfad[0] == '/' ) ) aPfad = aPfad.copy(1); } while (!aPfad.isEmpty()); // insert main entry itself if ( aStack.Empty() ) { eFlag = FSYS_FLAG_CURRENT; aName = rtl::OString(); } else { eFlag = aStack.Top()->eFlag; aName = aStack.Top()->aName; delete aStack.Pop(); } // Get parent entries from stack DirEntry** pTemp = &pParent; while ( !aStack.Empty() ) { *pTemp = aStack.Pop(); pTemp = &( (*pTemp)->pParent ); } return FSYS_ERR_OK; #endif } static FSysPathStyle GetStyle( FSysPathStyle eStyle ) { if ( eStyle == FSYS_STYLE_HOST || eStyle == FSYS_STYLE_DETECT ) return DEFSTYLE; else return eStyle; } /** Convert name to match OS norm. */ void DirEntry::ImpTrim() { // Do not trim wildcard characters if ( ( aName.indexOf( '*' ) != -1 ) || ( aName.indexOf( '?' ) != -1 ) || ( aName.indexOf( ';' ) != -1 ) ) return; #if defined(WNT) if ( aName.getLength() > 254 ) { nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; aName = aName.copy(254); } #else if ( aName.getLength() > 250 ) { nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK; aName = aName.copy(250); } #endif } DirEntry::DirEntry( const rtl::OString& rName, DirEntryFlag eDirFlag ) : #ifdef FEAT_FSYS_DOUBLESPEED pStat( 0 ), #endif aName( rName ) { DBG_CTOR( DirEntry, ImpCheckDirEntry ); pParent = NULL; eFlag = eDirFlag; nError = FSYS_ERR_OK; ImpTrim(); } 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( const String& rInitName, FSysPathStyle eStyle ) #ifdef FEAT_FSYS_DOUBLESPEED : pStat( 0 ) #endif { DBG_CTOR( DirEntry, ImpCheckDirEntry ); (void) eStyle; // only used for DBG_UTIL pParent = NULL; // faster check for empty string if ( !rInitName.Len()) { eFlag = FSYS_FLAG_CURRENT; nError = FSYS_ERR_OK; return; } rtl::OString aTmpName(rtl::OUStringToOString(rInitName, osl_getThreadTextEncoding())); if (aTmpName.matchIgnoreAsciiCase(rtl::OString(RTL_CONSTASCII_STRINGPARAM("file:")))) { DBG_WARNING( "File URLs are not permitted but accepted" ); aTmpName = rtl::OUStringToOString(INetURLObject( rInitName ).PathToFileName(), osl_getThreadTextEncoding()); #ifdef DBG_UTIL eStyle = FSYS_STYLE_HOST; #endif } else { ::rtl::OUString aTmp; ::rtl::OUString aOInitName; if ( FileBase::getFileURLFromSystemPath( OUString( rInitName ), aTmp ) == FileBase::E_None ) { aOInitName = OUString( rInitName ); aTmpName = rtl::OUStringToOString(aOInitName, osl_getThreadTextEncoding()); } #ifdef DBG_UTIL if (eStyle == FSYS_STYLE_HOST && aTmpName.indexOf( "://" ) != -1) { rtl::OStringBuffer aErr(RTL_CONSTASCII_STRINGPARAM("DirEntries akzeptieren nur File URLS: ")); aErr.append(aTmpName); DBG_WARNING(aErr.getStr()); } #endif } nError = ImpParseName( aTmpName ); if ( nError != FSYS_ERR_OK ) eFlag = FSYS_FLAG_INVALID; } DirEntry::DirEntry( const rtl::OString& rInitName, FSysPathStyle eStyle ) #ifdef FEAT_FSYS_DOUBLESPEED : pStat( 0 ) #endif { DBG_CTOR( DirEntry, ImpCheckDirEntry ); (void) eStyle; // only used for DBG_UTIL pParent = NULL; // faster check for empty string if ( rInitName.isEmpty() ) { eFlag = FSYS_FLAG_CURRENT; nError = FSYS_ERR_OK; return; } rtl::OString aTmpName( rInitName ); if (aTmpName.matchIgnoreAsciiCase(rtl::OString(RTL_CONSTASCII_STRINGPARAM("file:")))) { DBG_WARNING( "File URLs are not permitted but accepted" ); aTmpName = rtl::OUStringToOString(INetURLObject( rInitName ).PathToFileName(), osl_getThreadTextEncoding()); #ifdef DBG_UTIL eStyle = FSYS_STYLE_HOST; #endif } #ifdef DBG_UTIL else { if( eStyle == FSYS_STYLE_HOST && rInitName.indexOf("://") != -1 ) { rtl::OStringBuffer aErr(RTL_CONSTASCII_STRINGPARAM("DirEntries akzeptieren nur File URLS: ")); aErr.append(rInitName); DBG_WARNING(aErr.getStr()); } } #endif nError = ImpParseName( aTmpName ); if ( nError != FSYS_ERR_OK ) eFlag = FSYS_FLAG_INVALID; } 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() { DBG_DTOR( DirEntry, ImpCheckDirEntry ); delete pParent; #ifdef FEAT_FSYS_DOUBLESPEED delete pStat; #endif } const DirEntry* DirEntry::ImpGetTopPtr() const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); const DirEntry *pTemp = this; while ( pTemp->pParent ) pTemp = pTemp->pParent; return pTemp; } DirEntry* DirEntry::ImpGetTopPtr() { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); DirEntry *pTemp = this; while ( pTemp->pParent ) pTemp = pTemp->pParent; return pTemp; } 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.isEmpty() ) { pParent = 0; delete pNewParent; } else pParent = pNewParent; return pTemp; } sal_Bool DirEntry::Exists( FSysAccess nAccess ) const { static osl::Mutex aLocalMutex; osl::MutexGuard aGuard( aLocalMutex ); if ( !IsValid() ) return sal_False; #if defined WNT // get special file names from system if ( aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("CLOCK$")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("CON")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("AUX")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("COM1")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("COM2")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("COM3")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("COM4")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("LPT1")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("LPT2")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("LPT3")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("NUL")) || aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("PRN")) ) 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 if ( 0 != ( eKind & FSYS_KIND_DEV ) ) { return DRIVE_EXISTS( ImpGetTopPtr()->aName[0] ); } #endif return 0 != ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) ); } sal_Bool DirEntry::First() { FSysFailOnErrorImpl(); String aUniPathName( GetPath().GetFull() ); rtl::OString aPathName(rtl::OUStringToOString(aUniPathName, osl_getThreadTextEncoding())); DIR *pDir = opendir(aPathName.getStr()); if ( pDir ) { WildCard aWildeKarte(rtl::OStringToOUString(CMP_LOWER(aName), osl_getThreadTextEncoding())); for ( dirent* pEntry = readdir( pDir ); pEntry; pEntry = readdir( pDir ) ) { rtl::OString aFound(pEntry->d_name); if (aWildeKarte.Matches(rtl::OStringToOUString(CMP_LOWER(aFound), osl_getThreadTextEncoding()))) { aName = aFound; closedir( pDir ); return sal_True; } } closedir( pDir ); } return sal_False; } String DirEntry::GetFull( FSysPathStyle eStyle, sal_Bool bWithDelimiter, sal_uInt16 nMaxChars ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); rtl::OStringBuffer aBuf; eStyle = GetStyle( eStyle ); if ( pParent ) { if ( ( pParent->eFlag == FSYS_FLAG_ABSROOT || pParent->eFlag == FSYS_FLAG_RELROOT || pParent->eFlag == FSYS_FLAG_VOLUME ) ) { aBuf.append(rtl::OUStringToOString(pParent->GetName( eStyle ), osl_getThreadTextEncoding())); aBuf.append(rtl::OUStringToOString(GetName( eStyle ), osl_getThreadTextEncoding())); } else { aBuf.append(rtl::OUStringToOString(pParent->GetFull( eStyle ), osl_getThreadTextEncoding())); aBuf.append(ACCESSDELIM_C(eStyle)); aBuf.append(rtl::OUStringToOString(GetName( eStyle ), osl_getThreadTextEncoding())); } } else { aBuf.append(rtl::OUStringToOString(GetName(eStyle), osl_getThreadTextEncoding())); } //! Hack if ( bWithDelimiter ) if ( aBuf[aBuf.getLength()-1] != ACCESSDELIM_C(eStyle) ) aBuf.append(ACCESSDELIM_C(eStyle)); rtl::OString aRet = aBuf.makeStringAndClear(); // HACK if ( nMaxChars < STRING_MAXLEN ) aRet = ImplCutPath( aRet, nMaxChars, ACCESSDELIM_C(eStyle) ); return rtl::OStringToOUString(aRet, osl_getThreadTextEncoding()); } DirEntry DirEntry::GetPath() const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); if ( pParent ) return DirEntry( *pParent ); return DirEntry(); } String DirEntry::GetExtension( char cSep ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); const char *p0 = aName.getStr(); const char *p1 = p0 + aName.getLength() - 1; while ( p1 >= p0 && *p1 != cSep ) p1--; if ( p1 >= p0 ) { // found a cSep at position p1 return rtl::OStringToOUString(aName.copy(p1 - p0 + 1), osl_getThreadTextEncoding()); } return String(); } String DirEntry::GetBase( char cSep ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); const char *p0 = aName.getStr(); const char *p1 = p0 + aName.getLength() - 1; while ( p1 >= p0 && *p1 != cSep ) p1--; if ( p1 >= p0 ) { // found a cSep at position p1 return rtl::OStringToOUString(aName.copy(0, p1 - p0), osl_getThreadTextEncoding()); } // did not find a cSep return rtl::OStringToOUString(aName, osl_getThreadTextEncoding()); } String DirEntry::GetName( FSysPathStyle eStyle ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); rtl::OStringBuffer aRet; eStyle = GetStyle( eStyle ); switch( eFlag ) { case FSYS_FLAG_PARENT: aRet.append(ACTPARENT(eStyle)); break; case FSYS_FLAG_ABSROOT: { aRet.append(aName); aRet.append(ACCESSDELIM_C(eStyle)); break; } case FSYS_FLAG_INVALID: case FSYS_FLAG_VOLUME: { aRet.append(aName); break; } case FSYS_FLAG_RELROOT: if ( aName.isEmpty() ) { aRet.append(ACTCURRENT(eStyle)); break; } default: aRet.append(aName); break; } return rtl::OStringToOUString(aRet.makeStringAndClear(), osl_getThreadTextEncoding()); } 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.isEmpty() ); #endif } 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 = rtl::OString(); } } else { eFlag = FSYS_FLAG_CURRENT; aName = rtl::OString(); delete pParent; pParent = NULL; } return aOldName; } sal_Bool DirEntry::operator==( const DirEntry& rEntry ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); // test whether 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; const DirEntry *pThis = (DirEntry *)this; const 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& DirEntry::operator=( const DirEntry& rEntry ) { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); if ( this == &rEntry ) return *this; if ( rEntry.nError != FSYS_ERR_OK ) { OSL_FAIL("Zuweisung mit invalidem DirEntry"); nError = rEntry.nError; return *this; } // set name and type, but keep refs 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 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(); if ( (eFlag == FSYS_FLAG_RELROOT && aName.isEmpty()) || ( (!pEntryTop->aName.isEmpty() || ((rEntry.Level()>1)?(rEntry[rEntry.Level()-2].aName.equalsIgnoreAsciiCase(RFS_IDENTIFIER)):sal_False)) && (pEntryTop->eFlag == FSYS_FLAG_ABSROOT || pEntryTop->eFlag == FSYS_FLAG_RELROOT || pEntryTop->eFlag == FSYS_FLAG_VOLUME) ) ) { return rEntry; } // something + "." (=> pEntryTop == &rEntry) if (pEntryTop->eFlag == FSYS_FLAG_RELROOT && pEntryTop->aName.isEmpty()) { DBG_ASSERT( pEntryTop == &rEntry, "DirEntry::op+ buggy" ); return *this; } // root += ".." (=> impossible) if ( pEntryTop->eFlag == FSYS_FLAG_PARENT && pThisTop == this && ( eFlag == FSYS_FLAG_ABSROOT ) ) return DirEntry( FSYS_FLAG_INVALID ); // something += abs (=> only append device if existant) if ( pEntryTop->eFlag == FSYS_FLAG_ABSROOT ) { rtl::OString aDevice; if ( pThisTop->eFlag == FSYS_FLAG_ABSROOT ) aDevice = pThisTop->aName; DirEntry aRet = rEntry; if ( !aDevice.isEmpty() ) aRet.ImpGetTopPtr()->aName = aDevice; return aRet; } // something += ".." (=> break apart) 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 ); } // otherwise append consecutively DirEntry aRet( rEntry ); DirEntry *pTop = aRet.ImpGetTopPtr(); pTop->pParent = new DirEntry( *this ); return aRet; } DirEntry &DirEntry::operator+=( const DirEntry& rEntry ) { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); return *this = *this + rEntry; } String DirEntry::GetAccessDelimiter( FSysPathStyle eFormatter ) { return rtl::OUString( ACCESSDELIM_C( GetStyle( eFormatter ) ) ); } 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; } rtl::OStringBuffer aBuf(aName); // search cSep within aName const sal_Char *p0 = aBuf.getStr(); const sal_Char *p1 = p0 + aBuf.getLength() - 1; while ( p1 >= p0 && *p1 != cSep ) p1--; if ( p1 >= p0 ) { // found a cSep on position p1 sal_Int32 n = static_cast( p1 - p0 + 1 - ( rExtension.Len() ? 0 : 1 )); aBuf.remove(n, aBuf.getLength()-n); } else if ( rExtension.Len() ) { // no cSep was found aBuf.append(cSep); } aBuf.append(rtl::OUStringToOString(rExtension, osl_getThreadTextEncoding())); aName = aBuf.makeStringAndClear(); } void DirEntry::SetName( const String& rName, FSysPathStyle eFormatter ) { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); if ( eFormatter == FSYS_STYLE_HOST || eFormatter == FSYS_STYLE_DETECT ) eFormatter = DEFSTYLE; sal_Char cAccDelim(ACCESSDELIM_C(eFormatter)); if ( (eFlag != FSYS_FLAG_NORMAL) || (aName.indexOf(':') != -1) || (aName.indexOf(cAccDelim) != -1) ) { eFlag = FSYS_FLAG_INVALID; } else { aName = rtl::OUStringToOString(rName, osl_getThreadTextEncoding()); } } 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.indexOf( '*' ) != -1 || aName.indexOf( '?' ) != -1; if ( !cDelim ) cDelim = SEARCHDELIM(DEFSTYLE)[0]; rtl::OString aThis = rtl::OStringBuffer() .append(ACCESSDELIM_C(DEFSTYLE)) .append(rtl::OUStringToOString(GetFull(), osl_getThreadTextEncoding())) .makeStringAndClear(); sal_Int32 nIndex = 0; do { rtl::OStringBuffer aPath(rtl::OUStringToOString(rPfad, osl_getThreadTextEncoding()).getToken( 0, cDelim, nIndex )); if ( aPath.getLength() ) { if (aPath[aPath.getLength()-1] == ACCESSDELIM_C(DEFSTYLE)) aPath.remove(aPath.getLength()-1, 1); aPath.append(aThis); DirEntry aEntry(rtl::OStringToOUString( aPath.makeStringAndClear(), osl_getThreadTextEncoding())); if ( aEntry.ToAbs() && ( ( !bWild && aEntry.Exists() ) || ( bWild && aEntry.First() ) ) ) { (*this) = aEntry; return sal_True; } } } while ( nIndex >= 0 ); return sal_False; } #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.isEmpty() ) return DirEntry( pTop->aName, FSYS_FLAG_VOLUME ); else return DirEntry( rtl::OString(), FSYS_FLAG_INVALID ); } #endif String DirEntry::GetSearchDelimiter( FSysPathStyle eFormatter ) { return rtl::OStringToOUString(rtl::OString(SEARCHDELIM(GetStyle(eFormatter))), osl_getThreadTextEncoding()); } namespace { struct TempNameBase_Impl : public rtl::Static< DirEntry, TempNameBase_Impl > {}; } DirEntry DirEntry::TempName( DirEntryKind eKind ) const { // use base-temp-dir if necessary 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(); } rtl::OString aDirName; char *ret_val; size_t i; // determine Directory, Prefix and Extension char pfx[6]; char ext[5]; const char *dir; const char *pWild = strchr( aName.getStr(), '*' ); if ( !pWild ) pWild = strchr( aName.getStr(), '?' ); if ( pWild ) { if ( pParent ) aDirName = rtl::OUStringToOString(pParent->GetFull(), osl_getThreadTextEncoding()); strncpy( pfx, aName.getStr(), Min( (int)5, (int)(pWild-aName.getStr()) ) ); pfx[ pWild-aName.getStr() ] = 0; const char *pExt = strchr( pWild, '.' ); if ( pExt ) { strncpy( ext, pExt, 4 ); ext[4] = 0; } else strcpy( ext, ".tmp" ); } else { aDirName = rtl::OUStringToOString(GetFull(), osl_getThreadTextEncoding()); strcpy( pfx, "lo" ); strcpy( ext, ".tmp" ); } dir = aDirName.getStr(); char sBuf[_MAX_PATH]; if ( eFlag == FSYS_FLAG_CURRENT || ( !pParent && pWild ) ) dir = TempDirImpl(sBuf); 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) 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" */ #ifdef _WIN32 /* Milliseconds !! */ static unsigned long u = GetTickCount(); unsigned long mypid = static_cast(_getpid()); #else /* Microseconds !! */ static unsigned long u = clock(); unsigned long mypid = static_cast(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); if ( FSYS_KIND_DIR == eKind ) { if (0 == _mkdir(rtl::OUStringToOString(aRedirected, osl_getThreadTextEncoding()).getStr())) { aRet = DirEntry( aRetVal ); break; } } else { #if defined(UNX) if (access(rtl::OUStringToOString(aRedirected, osl_getThreadTextEncoding()).getStr(), F_OK)) { aRet = DirEntry( aRetVal ); break; } #else struct stat aStat; if (stat(rtl::OUStringToOString(aRedirected, osl_getThreadTextEncoding()).getStr(), &aStat)) { aRet = DirEntry( aRetVal ); break; } #endif } } } delete[] ret_val; ret_val = 0; } return aRet; } 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; } sal_Bool DirEntry::MakeDir( sal_Bool bSloppy ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); // fast check if exists 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 ) { // Create path to dir if ( pNewDir->pParent && !pNewDir->pParent->MakeDir(sal_False) ) return sal_False; // create dir ourselves if ( 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()); rtl::OString bDirName(rtl::OUStringToOString(aDirName, osl_getThreadTextEncoding())); #ifdef WIN32 SetLastError(0); #endif sal_Bool bResult = (0 == _mkdir(bDirName.getStr())); if ( !bResult ) { #ifdef WIN32 ((DirEntry *)this)->SetError( Sys2SolarError_Impl( GetLastError() ) ); #else ((DirEntry *)this)->SetError( Sys2SolarError_Impl( errno ) ); #endif } return bResult; } } } return sal_True; } FSysError DirEntry::CopyTo( const DirEntry& rDest, FSysAction nActions ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); if ( FSYS_ACTION_COPYFILE != (nActions & FSYS_ACTION_COPYFILE) ) #ifdef UNX { // create hardlink // redirection missing rtl::OString aThis(rtl::OUStringToOString(GetFull(), osl_getThreadTextEncoding())); rtl::OString aDest(rtl::OUStringToOString(rDest.GetFull(), osl_getThreadTextEncoding())); if (link(aThis.getStr(), aDest.getStr()) == -1) return Sys2SolarError_Impl( errno ); else return FSYS_ERR_OK; } #else return FSYS_ERR_NOTSUPPORTED; #endif FileCopier fc(*this, rDest); return fc.Execute(nActions); } #if defined WNT || defined UNX FSysError DirEntry::MoveTo( const DirEntry& rNewName ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); DirEntry aDest(rNewName); FileStat aDestStat(rNewName); if ( aDestStat.IsKind(FSYS_KIND_DIR ) ) { aDest += DirEntry(rtl::OStringToOUString(aName, osl_getThreadTextEncoding())); } if ( aDest.Exists() ) { return FSYS_ERR_ALREADYEXISTS; } FSysFailOnErrorImpl(); String aFrom( GetFull() ); String aTo( aDest.GetFull() ); rtl::OString bFrom(rtl::OUStringToOString(aFrom, osl_getThreadTextEncoding())); rtl::OString bTo(rtl::OUStringToOString(aTo, osl_getThreadTextEncoding())); #ifdef WNT // MoveTo nun atomar SetLastError(0); DirEntry aFromDevice(rtl::OStringToOUString(bFrom, osl_getThreadTextEncoding())); DirEntry aToDevice(rtl::OStringToOUString(bTo,osl_getThreadTextEncoding())); aFromDevice.ToAbs(); aToDevice.ToAbs(); aFromDevice=aFromDevice.GetDevice(); aToDevice=aToDevice.GetDevice(); if (aFromDevice==aToDevice) { // same device, use intra-device-move with MoveFile MoveFile( bFrom.getStr(), bTo.getStr() ); // Note: MoveFile is buggy for cross-device operations. // Return value is TRUE, even if the operation was only partially successful. // MoveFile has varying behavior between differing NT-versions. return Sys2SolarError_Impl( GetLastError() ); } else { // Not the same device, use inter-device-move with copy/delete FSysError nCopyError = CopyTo(rNewName, FSYS_ACTION_COPYFILE); DirEntry aKill(rtl::OStringToOUString(bTo, osl_getThreadTextEncoding())); FileStat aKillStat(String(rtl::OStringToOUString(bTo, osl_getThreadTextEncoding()))); if ( aKillStat.IsKind(FSYS_KIND_DIR ) ) { aKill += String(rtl::OStringToOUString(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.getStr(), bTo.getStr() ) ) ) #if !defined(UNX) return Sys2SolarError_Impl( GetLastError() ); #else { if( errno == EXDEV ) // simple rename does not work cross device { FILE *fpIN = fopen( bFrom.getStr(), "r" ); FILE *fpOUT = fopen( bTo.getStr(), "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 ); // Error in fwrite ? if( nWritten < nBytes ) { nErr = errno; break; } } fclose( fpIN ); fclose( fpOUT ); if ( nErr ) { unlink( bTo.getStr() ); return Sys2SolarError_Impl( nErr ); } else { unlink( bFrom.getStr() ); } } else { if ( fpIN ) fclose( fpIN ); if ( fpOUT ) fclose( fpOUT ); return Sys2SolarError_Impl( EXDEV ); } } else { return Sys2SolarError_Impl( errno ); } } #endif #endif // For the WNT case we always return already above, so avoid warning // C4702: unreachable code. Possibly also in non-WNT cases we always // return already above, but gcc apparently doesn't mind. #ifndef WNT return ERRCODE_NONE; #endif } #endif FSysError DirEntry::Kill( FSysAction nActions ) const { DBG_CHKTHIS( DirEntry, ImpCheckDirEntry ); FSysError eError = FSYS_ERR_OK; FSysFailOnErrorImpl(); // Terminate name string with two '0' String aTmpName( GetFull() ); rtl::OString bTmpName(rtl::OUStringToOString(aTmpName, osl_getThreadTextEncoding())); char *pName = new char[bTmpName.getLength()+2]; strcpy( pName, bTmpName.getStr() ); pName[bTmpName.getLength()+1] = (char) 0; // delete read-only files as well sal_Bool isReadOnly = FileStat::GetReadOnlyFlag(*this); if (isReadOnly) { FileStat::SetReadOnlyFlag(*this, sal_False); } // directory? if ( FileStat( *this ).IsKind(FSYS_KIND_DIR) ) { // Delete recursively? 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); } } // remove Dir myself #ifdef WIN32 SetLastError(0); #endif if ( eError == FSYS_ERR_OK && 0 != _rmdir( (char*) pName ) ) { // Change CWD if deletion failed #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) ) { #if 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; } } } // restore original read-only flag upon error if ( isReadOnly && (eError!=ERRCODE_NONE) ) { FileStat::SetReadOnlyFlag(*this, isReadOnly); } delete[] pName; return eError; } /** Check if rSubEntry is (in)directly beneath *this */ 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; } 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; } sal_Bool DirEntry::IsValid() const { return (nError == FSYS_ERR_OK); } #if defined(DBG_UTIL) void FSysTest() { } #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */