Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #if !defined UNX
21 : #ifdef WNT
22 : #include <windows.h>
23 : #undef GetObject
24 : #endif
25 : #include <io.h>
26 : #include <process.h>
27 : #endif
28 :
29 : #if defined(UNX)
30 : #include <unistd.h>
31 : #include <sys/types.h>
32 : #include <sys/stat.h>
33 : #endif
34 :
35 : #include <ctype.h>
36 : #include <errno.h>
37 : #include <stdlib.h>
38 : #include <stdio.h>
39 : #include <string.h>
40 : #include <tools/debug.hxx>
41 : #include "comdep.hxx"
42 : #include <tools/fsys.hxx>
43 : #define _TOOLS_HXX
44 : #include <tools/urlobj.hxx>
45 : #include <vector>
46 :
47 : #ifdef UNX
48 : #define _MAX_PATH 260
49 : #endif
50 :
51 : #include <tools/stream.hxx>
52 : #include <osl/mutex.hxx>
53 : #include <osl/file.hxx>
54 : #include <rtl/instance.hxx>
55 : #include <comphelper/string.hxx>
56 :
57 : using namespace osl;
58 : using ::rtl::OUString;
59 :
60 : int ApiRet2ToSolarError_Impl( int nApiRet );
61 :
62 32 : int Sys2SolarError_Impl( int nSysErr )
63 : {
64 32 : switch ( nSysErr )
65 : {
66 : #ifdef WNT
67 : case NO_ERROR: return ERRCODE_NONE;
68 : case ERROR_INVALID_FUNCTION: return ERRCODE_IO_GENERAL;
69 : case ERROR_FILE_NOT_FOUND: return ERRCODE_IO_NOTEXISTS;
70 : case ERROR_PATH_NOT_FOUND: return ERRCODE_IO_NOTEXISTSPATH;
71 : case ERROR_TOO_MANY_OPEN_FILES: return ERRCODE_IO_TOOMANYOPENFILES;
72 : case ERROR_ACCESS_DENIED: return ERRCODE_IO_ACCESSDENIED;
73 : case ERROR_INVALID_HANDLE: return ERRCODE_IO_GENERAL;
74 : case ERROR_NOT_ENOUGH_MEMORY: return ERRCODE_IO_OUTOFMEMORY;
75 : case ERROR_INVALID_BLOCK: return ERRCODE_IO_GENERAL;
76 : case ERROR_BAD_FORMAT: return ERRCODE_IO_WRONGFORMAT;
77 : case ERROR_INVALID_ACCESS: return ERRCODE_IO_ACCESSDENIED;
78 : case ERROR_INVALID_DRIVE: return ERRCODE_IO_INVALIDDEVICE;
79 : case ERROR_CURRENT_DIRECTORY: return ERRCODE_IO_CURRENTDIR;
80 : case ERROR_NOT_SAME_DEVICE: return ERRCODE_IO_NOTSAMEDEVICE;
81 : case ERROR_WRITE_PROTECT: return ERRCODE_IO_CANTWRITE;
82 : case ERROR_BAD_UNIT: return ERRCODE_IO_INVALIDDEVICE;
83 : case ERROR_NOT_READY: return ERRCODE_IO_DEVICENOTREADY;
84 : case ERROR_BAD_COMMAND: return ERRCODE_IO_GENERAL;
85 : case ERROR_CRC: return ERRCODE_IO_BADCRC;
86 : case ERROR_BAD_LENGTH: return ERRCODE_IO_INVALIDLENGTH;
87 : case ERROR_SEEK: return ERRCODE_IO_CANTSEEK;
88 : case ERROR_NOT_DOS_DISK: return ERRCODE_IO_WRONGFORMAT;
89 : case ERROR_SECTOR_NOT_FOUND: return ERRCODE_IO_GENERAL;
90 : case ERROR_WRITE_FAULT: return ERRCODE_IO_CANTWRITE;
91 : case ERROR_READ_FAULT: return ERRCODE_IO_CANTREAD;
92 : case ERROR_GEN_FAILURE: return ERRCODE_IO_GENERAL;
93 : case ERROR_SHARING_VIOLATION: return ERRCODE_IO_LOCKVIOLATION;
94 : case ERROR_LOCK_VIOLATION: return ERRCODE_IO_LOCKVIOLATION;
95 : case ERROR_WRONG_DISK: return ERRCODE_IO_INVALIDDEVICE;
96 : case ERROR_NOT_SUPPORTED: return ERRCODE_IO_NOTSUPPORTED;
97 : #else
98 0 : case 0: return ERRCODE_NONE;
99 32 : case ENOENT: return ERRCODE_IO_NOTEXISTS;
100 0 : case EACCES: return ERRCODE_IO_ACCESSDENIED;
101 0 : case EEXIST: return ERRCODE_IO_ALREADYEXISTS;
102 0 : case EINVAL: return ERRCODE_IO_INVALIDPARAMETER;
103 0 : case EMFILE: return ERRCODE_IO_TOOMANYOPENFILES;
104 0 : case ENOMEM: return ERRCODE_IO_OUTOFMEMORY;
105 0 : case ENOSPC: return ERRCODE_IO_OUTOFSPACE;
106 : #endif
107 : }
108 :
109 : OSL_TRACE( "FSys: unknown system error %d occurred", nSysErr );
110 0 : return FSYS_ERR_UNKNOWN;
111 : }
112 :
113 : class DirEntryStack
114 : {
115 : private:
116 : ::std::vector< DirEntry* > maStack;
117 :
118 : public:
119 36692 : DirEntryStack() {};
120 : ~DirEntryStack();
121 :
122 : inline void Push( DirEntry *pEntry );
123 : inline DirEntry* Pop();
124 : inline DirEntry* Top();
125 : inline DirEntry* Bottom();
126 : inline bool Empty();
127 : inline void Clear();
128 : };
129 :
130 242282 : inline void DirEntryStack::Push( DirEntry *pEntry )
131 : {
132 242282 : maStack.push_back( pEntry );
133 242282 : }
134 :
135 242282 : inline DirEntry* DirEntryStack::Pop()
136 : {
137 242282 : DirEntry* pEntry = NULL;
138 242282 : if ( !maStack.empty() ) {
139 242282 : pEntry = maStack.back();
140 242282 : maStack.pop_back();
141 : }
142 242282 : return pEntry;
143 : }
144 :
145 73384 : inline DirEntry* DirEntryStack::Top()
146 : {
147 73384 : return maStack.empty() ? NULL : maStack.back();
148 : }
149 :
150 : inline DirEntry* DirEntryStack::Bottom()
151 : {
152 : return maStack.empty() ? NULL : maStack.front();
153 : }
154 :
155 278974 : inline bool DirEntryStack::Empty()
156 : {
157 278974 : return maStack.empty();
158 : }
159 :
160 : inline void DirEntryStack::Clear()
161 : {
162 : maStack.clear();
163 : }
164 :
165 : DBG_NAME( DirEntry );
166 :
167 73384 : DirEntryStack::~DirEntryStack()
168 : {
169 36692 : maStack.clear();
170 36692 : }
171 :
172 : #ifdef DBG_UTIL
173 : /** Check DirEntry for DBG_UTIL
174 :
175 : @param p Pointer to DirEntry
176 : @return char* Error-TExtension or NULL
177 : */
178 : const char* ImpCheckDirEntry( const void* p )
179 : {
180 : DirEntry* p0 = (DirEntry*)p;
181 :
182 : if ( p0->pParent )
183 : DBG_CHKOBJ( p0->pParent, DirEntry, ImpCheckDirEntry );
184 :
185 : return NULL;
186 : }
187 : #endif
188 :
189 : /** Insert "..." for max length of nMaxChars */
190 0 : rtl::OString ImplCutPath( const rtl::OString& rStr, sal_Int32 nMax, char cAccDel )
191 : {
192 0 : sal_Int32 nMaxPathLen = nMax;
193 0 : sal_Bool bInsertPrefix = sal_False;
194 0 : sal_Int32 nBegin = rStr.indexOf(cAccDel);
195 0 : rtl::OStringBuffer aCutPath(rStr);
196 :
197 0 : if( nBegin == -1 )
198 0 : nBegin = 0;
199 : else
200 0 : nMaxPathLen += 2; // Prefix <Disk>:
201 :
202 0 : while( aCutPath.getLength() > nMaxPathLen )
203 : {
204 0 : sal_Int32 nEnd = aCutPath.toString().indexOf(cAccDel, nBegin + 1);
205 : sal_Int32 nCount;
206 :
207 0 : if ( nEnd != -1 )
208 : {
209 0 : nCount = nEnd - nBegin;
210 0 : aCutPath.remove(nBegin, nCount);
211 0 : bInsertPrefix = sal_True;
212 : }
213 : else
214 0 : break;
215 : }
216 :
217 0 : if ( aCutPath.getLength() > nMaxPathLen )
218 : {
219 0 : for ( sal_Int32 n = nMaxPathLen; n > nMaxPathLen/2; --n )
220 : {
221 0 : if (!comphelper::string::isalnumAscii(aCutPath[n]))
222 : {
223 0 : comphelper::string::truncateToLength(aCutPath, n);
224 0 : aCutPath.append(RTL_CONSTASCII_STRINGPARAM("..."));
225 0 : break;
226 : }
227 : }
228 : }
229 :
230 0 : if ( bInsertPrefix )
231 : {
232 0 : rtl::OStringBuffer aIns;
233 0 : aIns.append(cAccDel).append(RTL_CONSTASCII_STRINGPARAM("..."));
234 0 : aCutPath.insert(nBegin, aIns.makeStringAndClear());
235 : }
236 :
237 0 : return aCutPath.makeStringAndClear();
238 : }
239 :
240 36692 : FSysError DirEntry::ImpParseName( const rtl::OString& rPfad )
241 : {
242 : #if defined(WNT)
243 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
244 :
245 : // put single names onto stack
246 : String aPfad(rtl::OStringToOUString(rPfad, osl_getThreadTextEncoding()));
247 : DirEntryStack aStack;
248 :
249 : do
250 : {
251 : // split name before first "\\",
252 : // if '\\' is at beginning of string, name is set to '\\'.
253 : // ":" also splits the string and belongs to the name.
254 :
255 : // search first occurance of '\\', '/' or ':'
256 : sal_uInt16 nPos;
257 : for ( nPos = 0;
258 : nPos < aPfad.Len() && //?O
259 : aPfad.GetChar(nPos) != '\\' && aPfad.GetChar(nPos) != '/' && //?O
260 : aPfad.GetChar(nPos) != ':'; //?O
261 : nPos++ )
262 : /* do nothing */;
263 :
264 : // is the name a UNC pathname?
265 : if ( nPos == 0 && aPfad.Len() > 1 &&
266 : ( ( aPfad.GetChar(0) == '\\' && aPfad.GetChar(1) == '\\' ) ||
267 : ( aPfad.GetChar(0) == '/' && aPfad.GetChar(1) == '/' ) ) )
268 : {
269 : for ( nPos = 2; aPfad.Len() > nPos; ++nPos )
270 : if ( aPfad.GetChar(nPos) == '\\' || aPfad.GetChar(nPos) == '/' )
271 : break;
272 : aName = rtl::OUStringToOString(aPfad.Copy( 2, nPos-2 ), osl_getThreadTextEncoding());
273 : aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT ) );
274 : }
275 : // Is the name the root of the current drive?
276 : else if ( nPos == 0 && aPfad.Len() > 0 &&
277 : ( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) )
278 : {
279 : // Push root directory of current drive
280 : aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) );
281 : }
282 : else
283 : {
284 : // Is the name itself a drive?
285 : if ( nPos < aPfad.Len() && aPfad.GetChar(nPos) == ':' )
286 : {
287 : aName = rtl::OUStringToOString(aPfad.Copy( 0, nPos + 1 ), osl_getThreadTextEncoding());
288 :
289 : // Is the name the root of a drive?
290 : if ( (nPos + 1) < aPfad.Len() &&
291 : ( aPfad.GetChar(nPos+1) == '\\' || aPfad.GetChar(nPos+1) == '/' ) )
292 : {
293 : // unsupported if stack not empty or is a Novell format (URL)
294 : if ( !aStack.Empty() || aName.getLength() > 2 )
295 : {
296 : aName = rPfad;
297 : return FSYS_ERR_MISPLACEDCHAR;
298 : }
299 : // Push as root directory of drive
300 : aStack.Push( new DirEntry( aName, FSYS_FLAG_ABSROOT ) );
301 : }
302 : else
303 : {
304 : // clear stack if another drive is currently on it
305 : if ( !aStack.Empty() )
306 : {
307 : rtl::OString aThis(aStack.Bottom()->aName);
308 : aThis = aThis.toAsciiLowerCase();
309 : rtl::OString aOther(aName);
310 : aOther = aOther.toAsciiLowerCase();
311 : if (aThis.compareTo(aOther) != 0)
312 : aStack.Clear();
313 : }
314 :
315 : if ( aStack.Empty() )
316 : aStack.Push( new DirEntry( aName, FSYS_FLAG_RELROOT ) );
317 : }
318 : }
319 : // Name is not a drive
320 : else
321 : {
322 : // split the name without seperator
323 : aName = rtl::OUStringToOString(aPfad.Copy( 0, nPos ), osl_getThreadTextEncoding());
324 :
325 : // Is the name the current directory?
326 : if ( aName == "." )
327 : /* do nothing */;
328 :
329 : // Is the name the parent directory?
330 : else if ( aName == ".." )
331 : {
332 : // Is the stack empty, or a parent (or relative root) on it?
333 : if ( ( aStack.Empty() ) ||
334 : ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) ||
335 : ( aStack.Top()->eFlag == FSYS_FLAG_RELROOT ) )
336 : // add leading parent to stack
337 : aStack.Push( new DirEntry( FSYS_FLAG_PARENT ) );
338 :
339 : // It's an absolute root path
340 : else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT )
341 : {
342 : // Then there is no parent directory
343 : aName = rPfad;
344 : return FSYS_ERR_NOTEXISTS;
345 : }
346 : else
347 : // Otherwise removee parent TOS
348 : delete aStack.Pop();
349 : }
350 :
351 : else
352 : {
353 : // add ordinary entries to the stack
354 : DirEntry *pNew = new DirEntry( aName, FSYS_FLAG_NORMAL );
355 : if ( !pNew->IsValid() )
356 : {
357 : aName = rPfad;
358 : ErrCode eErr = pNew->GetError();
359 : delete pNew;
360 : return eErr;
361 : }
362 : aStack.Push( pNew );
363 : }
364 : }
365 : }
366 :
367 : // determine remainder of path
368 : aPfad.Erase( 0, nPos + 1 );
369 : while ( aPfad.Len() && ( aPfad.GetChar(0) == '\\' || aPfad.GetChar(0) == '/' ) )
370 : aPfad.Erase( 0, 1 );
371 : }
372 : while ( aPfad.Len() );
373 :
374 : sal_uIntPtr nErr = ERRCODE_NONE;
375 : // Set the main entry itself
376 : if ( aStack.Empty() )
377 : {
378 : eFlag = FSYS_FLAG_CURRENT;
379 : aName = rtl::OString();
380 : }
381 : else
382 : {
383 : eFlag = aStack.Top()->eFlag;
384 : aName = aStack.Top()->aName;
385 : nErr = aStack.Top()->nError;
386 : delete aStack.Pop();
387 : }
388 :
389 : // pop parent entry from stack
390 : DirEntry** pTemp = &pParent;
391 : while ( !aStack.Empty() )
392 : {
393 : *pTemp = aStack.Pop();
394 :
395 : // set member pointer to the pParent of the member's own parent
396 : pTemp = &( (*pTemp)->pParent );
397 : }
398 :
399 : // Does this describe a volume?
400 : if ( !pParent && eFlag == FSYS_FLAG_RELROOT && !aName.isEmpty() )
401 : eFlag = FSYS_FLAG_VOLUME;
402 :
403 : // use full aName if error code was set
404 : if ( nErr )
405 : aName = rPfad;
406 : return nErr;
407 : #else
408 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
409 :
410 : // Add single names to the stack
411 36692 : DirEntryStack aStack;
412 36692 : rtl::OString aPfad(rPfad);
413 242282 : do
414 : {
415 : // split names on the first occurance of "/",
416 : // if '/' starts the string, it itself becomes the name
417 :
418 : // search first occurance of "/"
419 : sal_uInt16 nPos;
420 3626943 : for ( nPos = 0;
421 3384661 : nPos < aPfad.getLength() && aPfad[nPos] != '/';
422 : nPos++ )
423 : /* do nothing */;
424 :
425 : // is the name the root of the current drive?
426 242282 : if ( nPos == 0 && !aPfad.isEmpty() && ( aPfad[0] == '/' ) )
427 : {
428 : // push root directory of current drive to stack
429 25261 : aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) );
430 : }
431 : else
432 : {
433 : // split name without seperator
434 217021 : aName = aPfad.copy(0, nPos);
435 :
436 : // Is the name the current directory?
437 217021 : if ( aName == "." )
438 : /* do nothing */;
439 :
440 : #ifdef UNX
441 : // Is the name the user's home directory?
442 217021 : else if ( aName == "~" )
443 : {
444 0 : DirEntry aHome( String( (const char *) getenv( "HOME" ), osl_getThreadTextEncoding()) );
445 0 : for ( sal_uInt16 n = aHome.Level(); n; --n )
446 0 : aStack.Push( new DirEntry( aHome[ (sal_uInt16) n-1 ] ) );
447 : }
448 : #endif
449 : // Is the name the current parent directory?
450 217021 : else if ( aName == ".." )
451 : {
452 : // Is the stack empty, or a parent (or relative root) is on top?
453 0 : if ( ( aStack.Empty() ) || ( aStack.Top()->eFlag == FSYS_FLAG_PARENT ) )
454 : {
455 : // push leading parents to stack
456 0 : aStack.Push( new DirEntry(rtl::OString(), FSYS_FLAG_PARENT) );
457 : }
458 : // Is the name an absolute root?
459 0 : else if ( aStack.Top()->eFlag == FSYS_FLAG_ABSROOT )
460 : {
461 : // they do not have parent directories
462 0 : return FSYS_ERR_NOTEXISTS;
463 : }
464 : else
465 : // otherwise remove parent TOS from stack
466 0 : delete aStack.Pop();
467 : }
468 : else
469 : {
470 217021 : DirEntry *pNew = NULL;
471 : // push ordinary entries on the stack
472 217021 : pNew = new DirEntry( aName, FSYS_FLAG_NORMAL );
473 217021 : if ( !pNew->IsValid() )
474 : {
475 0 : aName = rPfad;
476 0 : ErrCode eErr = pNew->GetError();
477 0 : delete pNew;
478 0 : return eErr;
479 : }
480 217021 : aStack.Push( pNew );
481 : }
482 : }
483 :
484 : // get remainder of path
485 242282 : aPfad = nPos < aPfad.getLength()
486 484564 : ? aPfad.copy(nPos + 1) : rtl::OString();
487 484564 : while ( !aPfad.isEmpty() && ( aPfad[0] == '/' ) )
488 0 : aPfad = aPfad.copy(1);
489 : }
490 242282 : while (!aPfad.isEmpty());
491 :
492 : // insert main entry itself
493 36692 : if ( aStack.Empty() )
494 : {
495 0 : eFlag = FSYS_FLAG_CURRENT;
496 0 : aName = rtl::OString();
497 : }
498 : else
499 : {
500 36692 : eFlag = aStack.Top()->eFlag;
501 36692 : aName = aStack.Top()->aName;
502 36692 : delete aStack.Pop();
503 : }
504 :
505 : // Get parent entries from stack
506 36692 : DirEntry** pTemp = &pParent;
507 278974 : while ( !aStack.Empty() )
508 : {
509 205590 : *pTemp = aStack.Pop();
510 205590 : pTemp = &( (*pTemp)->pParent );
511 : }
512 :
513 36692 : return FSYS_ERR_OK;
514 : #endif
515 : }
516 :
517 546288 : static FSysPathStyle GetStyle( FSysPathStyle eStyle )
518 : {
519 546288 : if ( eStyle == FSYS_STYLE_HOST || eStyle == FSYS_STYLE_DETECT )
520 52015 : return DEFSTYLE;
521 : else
522 494273 : return eStyle;
523 : }
524 :
525 : /** Convert name to match OS norm. */
526 217021 : void DirEntry::ImpTrim()
527 : {
528 : // Do not trim wildcard characters
529 651063 : if ( ( aName.indexOf( '*' ) != -1 ) ||
530 217021 : ( aName.indexOf( '?' ) != -1 ) ||
531 217021 : ( aName.indexOf( ';' ) != -1 ) )
532 217021 : return;
533 :
534 : #if defined(WNT)
535 : if ( aName.getLength() > 254 )
536 : {
537 : nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
538 : aName = aName.copy(254);
539 : }
540 : #else
541 217021 : if ( aName.getLength() > 250 )
542 : {
543 0 : nError = ERRCODE_IO_MISPLACEDCHAR|ERRCODE_WARNING_MASK;
544 0 : aName = aName.copy(250);
545 : }
546 : #endif
547 : }
548 :
549 217021 : DirEntry::DirEntry( const rtl::OString& rName, DirEntryFlag eDirFlag ) :
550 : #ifdef FEAT_FSYS_DOUBLESPEED
551 : pStat( 0 ),
552 : #endif
553 217021 : aName( rName )
554 : {
555 : DBG_CTOR( DirEntry, ImpCheckDirEntry );
556 :
557 217021 : pParent = NULL;
558 217021 : eFlag = eDirFlag;
559 217021 : nError = FSYS_ERR_OK;
560 :
561 217021 : ImpTrim();
562 217021 : }
563 :
564 524864 : DirEntry::DirEntry( const DirEntry& rOrig ) :
565 : #ifdef FEAT_FSYS_DOUBLESPEED
566 0 : pStat( rOrig.pStat ? new FileStat(*rOrig.pStat) : 0 ),
567 : #endif
568 524864 : aName( rOrig.aName )
569 : {
570 : DBG_CTOR( DirEntry, ImpCheckDirEntry );
571 :
572 524864 : eFlag = rOrig.eFlag;
573 524864 : nError = rOrig.nError;
574 :
575 524864 : if ( rOrig.pParent )
576 : {
577 457997 : pParent = new DirEntry( *rOrig.pParent );
578 : }
579 : else
580 : {
581 66867 : pParent = NULL;
582 : }
583 524864 : }
584 :
585 36692 : DirEntry::DirEntry( const String& rInitName, FSysPathStyle eStyle )
586 : #ifdef FEAT_FSYS_DOUBLESPEED
587 36692 : : pStat( 0 )
588 : #endif
589 : {
590 : DBG_CTOR( DirEntry, ImpCheckDirEntry );
591 :
592 : (void) eStyle; // only used for DBG_UTIL
593 :
594 36692 : pParent = NULL;
595 :
596 : // faster check for empty string
597 36692 : if ( !rInitName.Len())
598 : {
599 0 : eFlag = FSYS_FLAG_CURRENT;
600 0 : nError = FSYS_ERR_OK;
601 36692 : return;
602 : }
603 :
604 36692 : rtl::OString aTmpName(rtl::OUStringToOString(rInitName, osl_getThreadTextEncoding()));
605 36692 : if (aTmpName.matchIgnoreAsciiCase(rtl::OString(RTL_CONSTASCII_STRINGPARAM("file:"))))
606 : {
607 : DBG_WARNING( "File URLs are not permitted but accepted" );
608 0 : aTmpName = rtl::OUStringToOString(INetURLObject( rInitName ).PathToFileName(), osl_getThreadTextEncoding());
609 : #ifdef DBG_UTIL
610 : eStyle = FSYS_STYLE_HOST;
611 : #endif
612 : }
613 : else
614 : {
615 36692 : ::rtl::OUString aTmp;
616 36692 : ::rtl::OUString aOInitName;
617 36692 : if ( FileBase::getFileURLFromSystemPath( OUString( rInitName ), aTmp ) == FileBase::E_None )
618 : {
619 36692 : aOInitName = OUString( rInitName );
620 36692 : aTmpName = rtl::OUStringToOString(aOInitName, osl_getThreadTextEncoding());
621 36692 : }
622 :
623 : #ifdef DBG_UTIL
624 : if (eStyle == FSYS_STYLE_HOST && aTmpName.indexOf( "://" ) != -1)
625 : {
626 : rtl::OStringBuffer aErr(RTL_CONSTASCII_STRINGPARAM("DirEntries akzeptieren nur File URLS: "));
627 : aErr.append(aTmpName);
628 : DBG_WARNING(aErr.getStr());
629 : }
630 : #endif
631 : }
632 :
633 36692 : nError = ImpParseName( aTmpName );
634 :
635 36692 : if ( nError != FSYS_ERR_OK )
636 0 : eFlag = FSYS_FLAG_INVALID;
637 : }
638 :
639 0 : DirEntry::DirEntry( const rtl::OString& rInitName, FSysPathStyle eStyle )
640 : #ifdef FEAT_FSYS_DOUBLESPEED
641 0 : : pStat( 0 )
642 : #endif
643 : {
644 : DBG_CTOR( DirEntry, ImpCheckDirEntry );
645 :
646 : (void) eStyle; // only used for DBG_UTIL
647 :
648 0 : pParent = NULL;
649 :
650 : // faster check for empty string
651 0 : if ( rInitName.isEmpty() )
652 : {
653 0 : eFlag = FSYS_FLAG_CURRENT;
654 0 : nError = FSYS_ERR_OK;
655 0 : return;
656 : }
657 :
658 0 : rtl::OString aTmpName( rInitName );
659 0 : if (aTmpName.matchIgnoreAsciiCase(rtl::OString(RTL_CONSTASCII_STRINGPARAM("file:"))))
660 : {
661 : DBG_WARNING( "File URLs are not permitted but accepted" );
662 0 : aTmpName = rtl::OUStringToOString(INetURLObject( rInitName ).PathToFileName(), osl_getThreadTextEncoding());
663 : #ifdef DBG_UTIL
664 : eStyle = FSYS_STYLE_HOST;
665 : #endif
666 : }
667 : #ifdef DBG_UTIL
668 : else
669 : {
670 : if( eStyle == FSYS_STYLE_HOST && rInitName.indexOf("://") != -1 )
671 : {
672 : rtl::OStringBuffer aErr(RTL_CONSTASCII_STRINGPARAM("DirEntries akzeptieren nur File URLS: "));
673 : aErr.append(rInitName);
674 : DBG_WARNING(aErr.getStr());
675 : }
676 : }
677 : #endif
678 :
679 0 : nError = ImpParseName( aTmpName );
680 :
681 0 : if ( nError != FSYS_ERR_OK )
682 0 : eFlag = FSYS_FLAG_INVALID;
683 : }
684 :
685 26630 : DirEntry::DirEntry( DirEntryFlag eDirFlag )
686 : #ifdef FEAT_FSYS_DOUBLESPEED
687 26630 : : pStat( 0 )
688 : #endif
689 : {
690 : DBG_CTOR( DirEntry, ImpCheckDirEntry );
691 :
692 26630 : eFlag = eDirFlag;
693 26630 : nError = ( eFlag == FSYS_FLAG_INVALID ) ? FSYS_ERR_UNKNOWN : FSYS_ERR_OK;
694 26630 : pParent = NULL;
695 26630 : }
696 :
697 1610414 : DirEntry::~DirEntry()
698 : {
699 : DBG_DTOR( DirEntry, ImpCheckDirEntry );
700 :
701 805207 : delete pParent;
702 : #ifdef FEAT_FSYS_DOUBLESPEED
703 805207 : delete pStat;
704 : #endif
705 :
706 805207 : }
707 :
708 22204 : const DirEntry* DirEntry::ImpGetTopPtr() const
709 : {
710 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
711 :
712 22204 : const DirEntry *pTemp = this;
713 135235 : while ( pTemp->pParent )
714 90827 : pTemp = pTemp->pParent;
715 :
716 22204 : return pTemp;
717 : }
718 :
719 11493 : DirEntry* DirEntry::ImpGetTopPtr()
720 : {
721 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
722 :
723 11493 : DirEntry *pTemp = this;
724 23788 : while ( pTemp->pParent )
725 802 : pTemp = pTemp->pParent;
726 :
727 11493 : return pTemp;
728 : }
729 :
730 0 : DirEntry* DirEntry::ImpChangeParent( DirEntry* pNewParent, sal_Bool bNormalize )
731 : {
732 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
733 :
734 0 : DirEntry *pTemp = pParent;
735 0 : if ( bNormalize && pNewParent &&
736 0 : pNewParent->eFlag == FSYS_FLAG_RELROOT && pNewParent->aName.isEmpty() )
737 : {
738 0 : pParent = 0;
739 0 : delete pNewParent;
740 : }
741 : else
742 0 : pParent = pNewParent;
743 :
744 0 : return pTemp;
745 : }
746 :
747 1183 : sal_Bool DirEntry::Exists( FSysAccess nAccess ) const
748 : {
749 1183 : static osl::Mutex aLocalMutex;
750 1183 : osl::MutexGuard aGuard( aLocalMutex );
751 1183 : if ( !IsValid() )
752 0 : return sal_False;
753 :
754 : #if defined WNT
755 : // get special file names from system
756 : if ( aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("CLOCK$")) ||
757 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("CON")) ||
758 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("AUX")) ||
759 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("COM1")) ||
760 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("COM2")) ||
761 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("COM3")) ||
762 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("COM4")) ||
763 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("LPT1")) ||
764 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("LPT2")) ||
765 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("LPT3")) ||
766 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("NUL")) ||
767 : aName.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("PRN")) )
768 : return sal_True;
769 : #endif
770 :
771 : FSysFailOnErrorImpl();
772 1183 : DirEntryKind eKind = FileStat( *this, nAccess ).GetKind();
773 1183 : if ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) )
774 : {
775 329 : return sal_True;
776 : }
777 :
778 : #if defined WNT
779 : if ( 0 != ( eKind & FSYS_KIND_DEV ) )
780 : {
781 : return DRIVE_EXISTS( ImpGetTopPtr()->aName[0] );
782 : }
783 : #endif
784 :
785 854 : return 0 != ( eKind & ( FSYS_KIND_FILE | FSYS_KIND_DIR ) );
786 : }
787 :
788 0 : sal_Bool DirEntry::First()
789 : {
790 : FSysFailOnErrorImpl();
791 :
792 0 : String aUniPathName( GetPath().GetFull() );
793 0 : rtl::OString aPathName(rtl::OUStringToOString(aUniPathName, osl_getThreadTextEncoding()));
794 :
795 0 : DIR *pDir = opendir(aPathName.getStr());
796 0 : if ( pDir )
797 : {
798 0 : WildCard aWildeKarte(rtl::OStringToOUString(CMP_LOWER(aName), osl_getThreadTextEncoding()));
799 0 : for ( dirent* pEntry = readdir( pDir );
800 : pEntry;
801 : pEntry = readdir( pDir ) )
802 : {
803 0 : rtl::OString aFound(pEntry->d_name);
804 0 : if (aWildeKarte.Matches(rtl::OStringToOUString(CMP_LOWER(aFound), osl_getThreadTextEncoding())))
805 : {
806 0 : aName = aFound;
807 0 : closedir( pDir );
808 0 : return sal_True;
809 : }
810 0 : }
811 0 : closedir( pDir );
812 : }
813 0 : return sal_False;
814 : }
815 :
816 247713 : String DirEntry::GetFull( FSysPathStyle eStyle, sal_Bool bWithDelimiter,
817 : sal_uInt16 nMaxChars ) const
818 : {
819 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
820 :
821 247713 : rtl::OStringBuffer aBuf;
822 247713 : eStyle = GetStyle( eStyle );
823 247713 : if ( pParent )
824 : {
825 246560 : if ( ( pParent->eFlag == FSYS_FLAG_ABSROOT ||
826 : pParent->eFlag == FSYS_FLAG_RELROOT ||
827 : pParent->eFlag == FSYS_FLAG_VOLUME ) )
828 : {
829 32275 : aBuf.append(rtl::OUStringToOString(pParent->GetName( eStyle ), osl_getThreadTextEncoding()));
830 32275 : aBuf.append(rtl::OUStringToOString(GetName( eStyle ), osl_getThreadTextEncoding()));
831 : }
832 : else
833 : {
834 214285 : aBuf.append(rtl::OUStringToOString(pParent->GetFull( eStyle ), osl_getThreadTextEncoding()));
835 214285 : aBuf.append(ACCESSDELIM_C(eStyle));
836 214285 : aBuf.append(rtl::OUStringToOString(GetName( eStyle ), osl_getThreadTextEncoding()));
837 : }
838 : }
839 : else
840 : {
841 1153 : aBuf.append(rtl::OUStringToOString(GetName(eStyle), osl_getThreadTextEncoding()));
842 : }
843 :
844 : //! Hack
845 247713 : if ( bWithDelimiter )
846 0 : if ( aBuf[aBuf.getLength()-1] != ACCESSDELIM_C(eStyle) )
847 0 : aBuf.append(ACCESSDELIM_C(eStyle));
848 :
849 247713 : rtl::OString aRet = aBuf.makeStringAndClear();
850 :
851 : // HACK
852 247713 : if ( nMaxChars < STRING_MAXLEN )
853 0 : aRet = ImplCutPath( aRet, nMaxChars, ACCESSDELIM_C(eStyle) );
854 :
855 247713 : return rtl::OStringToOUString(aRet, osl_getThreadTextEncoding());
856 : }
857 :
858 40 : DirEntry DirEntry::GetPath() const
859 : {
860 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
861 :
862 40 : if ( pParent )
863 40 : return DirEntry( *pParent );
864 :
865 0 : return DirEntry();
866 : }
867 :
868 0 : String DirEntry::GetExtension( char cSep ) const
869 : {
870 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
871 :
872 0 : const char *p0 = aName.getStr();
873 0 : const char *p1 = p0 + aName.getLength() - 1;
874 0 : while ( p1 >= p0 && *p1 != cSep )
875 0 : p1--;
876 :
877 0 : if ( p1 >= p0 )
878 : {
879 : // found a cSep at position p1
880 : return rtl::OStringToOUString(aName.copy(p1 - p0 + 1),
881 0 : osl_getThreadTextEncoding());
882 : }
883 :
884 0 : return String();
885 : }
886 :
887 0 : String DirEntry::GetBase( char cSep ) const
888 : {
889 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
890 :
891 0 : const char *p0 = aName.getStr();
892 0 : const char *p1 = p0 + aName.getLength() - 1;
893 0 : while ( p1 >= p0 && *p1 != cSep )
894 0 : p1--;
895 :
896 0 : if ( p1 >= p0 )
897 : {
898 : // found a cSep at position p1
899 : return rtl::OStringToOUString(aName.copy(0, p1 - p0),
900 0 : osl_getThreadTextEncoding());
901 :
902 : }
903 : // did not find a cSep
904 0 : return rtl::OStringToOUString(aName, osl_getThreadTextEncoding());
905 : }
906 :
907 288640 : String DirEntry::GetName( FSysPathStyle eStyle ) const
908 : {
909 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
910 :
911 288640 : rtl::OStringBuffer aRet;
912 288640 : eStyle = GetStyle( eStyle );
913 :
914 288640 : switch( eFlag )
915 : {
916 : case FSYS_FLAG_PARENT:
917 0 : aRet.append(ACTPARENT(eStyle));
918 0 : break;
919 :
920 : case FSYS_FLAG_ABSROOT:
921 : {
922 32275 : aRet.append(aName);
923 32275 : aRet.append(ACCESSDELIM_C(eStyle));
924 32275 : break;
925 : }
926 :
927 : case FSYS_FLAG_INVALID:
928 : case FSYS_FLAG_VOLUME:
929 : {
930 0 : aRet.append(aName);
931 0 : break;
932 : }
933 :
934 : case FSYS_FLAG_RELROOT:
935 691 : if ( aName.isEmpty() )
936 : {
937 691 : aRet.append(ACTCURRENT(eStyle));
938 691 : break;
939 : }
940 :
941 : default:
942 255674 : aRet.append(aName);
943 255674 : break;
944 : }
945 :
946 : return rtl::OStringToOUString(aRet.makeStringAndClear(),
947 288640 : osl_getThreadTextEncoding());
948 : }
949 :
950 116042 : bool DirEntry::IsAbs() const
951 : {
952 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
953 :
954 : #ifdef UNX
955 116042 : return ( pParent ? pParent->IsAbs() : eFlag == FSYS_FLAG_ABSROOT );
956 : #else
957 : return ( pParent ? pParent->IsAbs() : eFlag == FSYS_FLAG_ABSROOT && !aName.isEmpty() );
958 : #endif
959 : }
960 :
961 0 : String DirEntry::CutName( FSysPathStyle eStyle )
962 : {
963 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
964 :
965 0 : eStyle = GetStyle( eStyle );
966 :
967 0 : String aOldName( GetName( eStyle ) );
968 :
969 0 : if ( pParent )
970 : {
971 0 : DirEntry *pOldParent = pParent;
972 0 : if ( pOldParent )
973 : {
974 0 : pParent = pOldParent->pParent;
975 0 : eFlag = pOldParent->eFlag;
976 0 : aName = pOldParent->aName;
977 0 : pOldParent->pParent = NULL;
978 0 : delete pOldParent;
979 : }
980 : else
981 : {
982 0 : eFlag = FSYS_FLAG_CURRENT;
983 0 : aName = rtl::OString();
984 : }
985 : }
986 : else
987 : {
988 0 : eFlag = FSYS_FLAG_CURRENT;
989 0 : aName = rtl::OString();
990 0 : delete pParent;
991 0 : pParent = NULL;
992 : }
993 :
994 0 : return aOldName;
995 : }
996 :
997 630 : sal_Bool DirEntry::operator==( const DirEntry& rEntry ) const
998 : {
999 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1000 :
1001 : // test whether the contents are textual the same
1002 :
1003 630 : if ( nError && ( nError == rEntry.nError ) )
1004 0 : return sal_True;
1005 630 : if ( nError || rEntry.nError ||
1006 : ( eFlag == FSYS_FLAG_INVALID ) ||
1007 : ( rEntry.eFlag == FSYS_FLAG_INVALID ) )
1008 0 : return sal_False;
1009 :
1010 630 : const DirEntry *pThis = (DirEntry *)this;
1011 630 : const DirEntry *pWith = (DirEntry *)&rEntry;
1012 1260 : while( pThis && pWith && (pThis->eFlag == pWith->eFlag) )
1013 : {
1014 630 : if ( CMP_LOWER(pThis->aName) != CMP_LOWER(pWith->aName) )
1015 630 : break;
1016 0 : pThis = pThis->pParent;
1017 0 : pWith = pWith->pParent;
1018 : }
1019 :
1020 630 : return ( !pThis && !pWith );
1021 : }
1022 :
1023 12101 : DirEntry& DirEntry::operator=( const DirEntry& rEntry )
1024 : {
1025 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1026 :
1027 12101 : if ( this == &rEntry )
1028 0 : return *this;
1029 12101 : if ( rEntry.nError != FSYS_ERR_OK ) {
1030 : OSL_FAIL("Zuweisung mit invalidem DirEntry");
1031 0 : nError = rEntry.nError;
1032 0 : return *this;
1033 : }
1034 :
1035 : // set name and type, but keep refs
1036 12101 : aName = rEntry.aName;
1037 12101 : eFlag = rEntry.eFlag;
1038 12101 : nError = FSYS_ERR_OK;
1039 :
1040 12101 : DirEntry *pOldParent = pParent;
1041 12101 : if ( rEntry.pParent )
1042 12101 : pParent = new DirEntry( *rEntry.pParent );
1043 : else
1044 0 : pParent = NULL;
1045 :
1046 12101 : if ( pOldParent )
1047 11310 : delete pOldParent;
1048 12101 : return *this;
1049 : }
1050 :
1051 11102 : DirEntry DirEntry::operator+( const DirEntry& rEntry ) const
1052 : {
1053 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1054 : #ifdef DBG_UTIL
1055 : static sal_Bool bTested = sal_False;
1056 : if ( !bTested )
1057 : {
1058 : bTested = sal_True;
1059 : FSysTest();
1060 : }
1061 : #endif
1062 :
1063 11102 : const DirEntry *pEntryTop = rEntry.ImpGetTopPtr();
1064 11102 : const DirEntry *pThisTop = ImpGetTopPtr();
1065 :
1066 22204 : if (
1067 0 : (eFlag == FSYS_FLAG_RELROOT && aName.isEmpty()) ||
1068 : (
1069 11102 : (!pEntryTop->aName.isEmpty() ||
1070 0 : ((rEntry.Level()>1)?(rEntry[rEntry.Level()-2].aName.equalsIgnoreAsciiCase(RFS_IDENTIFIER)):sal_False))
1071 : &&
1072 : (pEntryTop->eFlag == FSYS_FLAG_ABSROOT ||
1073 : pEntryTop->eFlag == FSYS_FLAG_RELROOT ||
1074 : pEntryTop->eFlag == FSYS_FLAG_VOLUME)
1075 : )
1076 : )
1077 : {
1078 0 : return rEntry;
1079 : }
1080 :
1081 : // something + "." (=> pEntryTop == &rEntry)
1082 11102 : if (pEntryTop->eFlag == FSYS_FLAG_RELROOT && pEntryTop->aName.isEmpty())
1083 : {
1084 : DBG_ASSERT( pEntryTop == &rEntry, "DirEntry::op+ buggy" );
1085 0 : return *this;
1086 : }
1087 :
1088 : // root += ".." (=> impossible)
1089 11102 : if ( pEntryTop->eFlag == FSYS_FLAG_PARENT && pThisTop == this &&
1090 : ( eFlag == FSYS_FLAG_ABSROOT ) )
1091 0 : return DirEntry( FSYS_FLAG_INVALID );
1092 :
1093 : // something += abs (=> only append device if existant)
1094 11102 : if ( pEntryTop->eFlag == FSYS_FLAG_ABSROOT )
1095 : {
1096 0 : rtl::OString aDevice;
1097 0 : if ( pThisTop->eFlag == FSYS_FLAG_ABSROOT )
1098 0 : aDevice = pThisTop->aName;
1099 0 : DirEntry aRet = rEntry;
1100 0 : if ( !aDevice.isEmpty() )
1101 0 : aRet.ImpGetTopPtr()->aName = aDevice;
1102 0 : return aRet;
1103 : }
1104 :
1105 : // something += ".." (=> break apart)
1106 11102 : if ( eFlag == FSYS_FLAG_NORMAL && pEntryTop->eFlag == FSYS_FLAG_PARENT )
1107 : {
1108 0 : String aConcated( GetFull() );
1109 0 : aConcated += ACCESSDELIM_C(FSYS_STYLE_HOST);
1110 0 : aConcated += rEntry.GetFull();
1111 0 : return DirEntry( aConcated );
1112 : }
1113 :
1114 : // otherwise append consecutively
1115 11102 : DirEntry aRet( rEntry );
1116 11102 : DirEntry *pTop = aRet.ImpGetTopPtr();
1117 11102 : pTop->pParent = new DirEntry( *this );
1118 :
1119 11102 : return aRet;
1120 : }
1121 :
1122 11102 : DirEntry &DirEntry::operator+=( const DirEntry& rEntry )
1123 : {
1124 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1125 :
1126 11102 : return *this = *this + rEntry;
1127 : }
1128 :
1129 61 : String DirEntry::GetAccessDelimiter( FSysPathStyle eFormatter )
1130 : {
1131 61 : return rtl::OUString( ACCESSDELIM_C( GetStyle( eFormatter ) ) );
1132 : }
1133 :
1134 1382 : void DirEntry::SetExtension( const String& rExtension, char cSep )
1135 : {
1136 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1137 :
1138 : // do not set extensions for drives
1139 1382 : if(eFlag == FSYS_FLAG_ABSROOT)
1140 : {
1141 0 : nError = FSYS_ERR_NOTSUPPORTED;
1142 1382 : return;
1143 : }
1144 :
1145 1382 : rtl::OStringBuffer aBuf(aName);
1146 :
1147 : // search cSep within aName
1148 1382 : const sal_Char *p0 = aBuf.getStr();
1149 1382 : const sal_Char *p1 = p0 + aBuf.getLength() - 1;
1150 8800 : while ( p1 >= p0 && *p1 != cSep )
1151 6036 : p1--;
1152 1382 : if ( p1 >= p0 )
1153 : {
1154 : // found a cSep on position p1
1155 :
1156 : sal_Int32 n = static_cast<sal_Int32>(
1157 752 : p1 - p0 + 1 - ( rExtension.Len() ? 0 : 1 ));
1158 :
1159 752 : aBuf.remove(n, aBuf.getLength()-n);
1160 : }
1161 630 : else if ( rExtension.Len() )
1162 : {
1163 : // no cSep was found
1164 630 : aBuf.append(cSep);
1165 : }
1166 :
1167 : aBuf.append(rtl::OUStringToOString(rExtension,
1168 1382 : osl_getThreadTextEncoding()));
1169 :
1170 1382 : aName = aBuf.makeStringAndClear();
1171 : }
1172 :
1173 0 : void DirEntry::SetName( const String& rName, FSysPathStyle eFormatter )
1174 : {
1175 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1176 :
1177 0 : if ( eFormatter == FSYS_STYLE_HOST || eFormatter == FSYS_STYLE_DETECT )
1178 0 : eFormatter = DEFSTYLE;
1179 0 : sal_Char cAccDelim(ACCESSDELIM_C(eFormatter));
1180 :
1181 0 : if ( (eFlag != FSYS_FLAG_NORMAL) ||
1182 0 : (aName.indexOf(':') != -1) ||
1183 0 : (aName.indexOf(cAccDelim) != -1) )
1184 : {
1185 0 : eFlag = FSYS_FLAG_INVALID;
1186 : }
1187 : else
1188 : {
1189 0 : aName = rtl::OUStringToOString(rName, osl_getThreadTextEncoding());
1190 : }
1191 0 : }
1192 :
1193 391 : sal_Bool DirEntry::Find( const String& rPfad, char cDelim )
1194 : {
1195 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1196 :
1197 391 : if ( ImpGetTopPtr()->eFlag == FSYS_FLAG_ABSROOT )
1198 62 : return sal_True;
1199 :
1200 329 : sal_Bool bWild = aName.indexOf( '*' ) != -1 ||
1201 329 : aName.indexOf( '?' ) != -1;
1202 :
1203 329 : if ( !cDelim )
1204 329 : cDelim = SEARCHDELIM(DEFSTYLE)[0];
1205 :
1206 : rtl::OString aThis = rtl::OStringBuffer()
1207 658 : .append(ACCESSDELIM_C(DEFSTYLE))
1208 : .append(rtl::OUStringToOString(GetFull(),
1209 987 : osl_getThreadTextEncoding()))
1210 329 : .makeStringAndClear();
1211 329 : sal_Int32 nIndex = 0;
1212 814 : do
1213 : {
1214 : rtl::OStringBuffer aPath(rtl::OUStringToOString(rPfad,
1215 1143 : osl_getThreadTextEncoding()).getToken( 0, cDelim, nIndex ));
1216 :
1217 1143 : if ( aPath.getLength() )
1218 : {
1219 1143 : if (aPath[aPath.getLength()-1] == ACCESSDELIM_C(DEFSTYLE))
1220 221 : aPath.remove(aPath.getLength()-1, 1);
1221 1143 : aPath.append(aThis);
1222 : DirEntry aEntry(rtl::OStringToOUString(
1223 1143 : aPath.makeStringAndClear(), osl_getThreadTextEncoding()));
1224 2286 : if ( aEntry.ToAbs() &&
1225 1143 : ( ( !bWild && aEntry.Exists() ) || ( bWild && aEntry.First() ) ) )
1226 : {
1227 329 : (*this) = aEntry;
1228 329 : return sal_True;
1229 1143 : }
1230 1143 : }
1231 : }
1232 : while ( nIndex >= 0 );
1233 0 : return sal_False;
1234 : }
1235 :
1236 : #ifndef UNX
1237 : DirEntry DirEntry::GetDevice() const
1238 : {
1239 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1240 :
1241 : const DirEntry *pTop = ImpGetTopPtr();
1242 :
1243 : if ( ( pTop->eFlag == FSYS_FLAG_ABSROOT || pTop->eFlag == FSYS_FLAG_RELROOT ) &&
1244 : !pTop->aName.isEmpty() )
1245 : return DirEntry( pTop->aName, FSYS_FLAG_VOLUME );
1246 : else
1247 : return DirEntry( rtl::OString(), FSYS_FLAG_INVALID );
1248 : }
1249 : #endif
1250 :
1251 9874 : String DirEntry::GetSearchDelimiter( FSysPathStyle eFormatter )
1252 : {
1253 9874 : return rtl::OStringToOUString(rtl::OString(SEARCHDELIM(GetStyle(eFormatter))), osl_getThreadTextEncoding());
1254 : }
1255 :
1256 : namespace
1257 : {
1258 : struct TempNameBase_Impl : public rtl::Static< DirEntry, TempNameBase_Impl > {};
1259 : }
1260 :
1261 40 : DirEntry DirEntry::TempName( DirEntryKind eKind ) const
1262 : {
1263 : // use base-temp-dir if necessary
1264 40 : const DirEntry &rEntry = TempNameBase_Impl::get();
1265 40 : if ( !pParent && FSYS_FLAG_CURRENT != rEntry.eFlag && FSYS_FLAG_ABSROOT != eFlag )
1266 : {
1267 0 : DirEntry aFactory( rEntry );
1268 0 : aFactory += GetName();
1269 0 : return aFactory.TempName();
1270 : }
1271 :
1272 40 : rtl::OString aDirName;
1273 : char *ret_val;
1274 : size_t i;
1275 :
1276 : // determine Directory, Prefix and Extension
1277 : char pfx[6];
1278 : char ext[5];
1279 : const char *dir;
1280 40 : const char *pWild = strchr( aName.getStr(), '*' );
1281 40 : if ( !pWild )
1282 40 : pWild = strchr( aName.getStr(), '?' );
1283 :
1284 40 : if ( pWild )
1285 : {
1286 0 : if ( pParent )
1287 0 : aDirName = rtl::OUStringToOString(pParent->GetFull(), osl_getThreadTextEncoding());
1288 0 : strncpy( pfx, aName.getStr(), Min( (int)5, (int)(pWild-aName.getStr()) ) );
1289 0 : pfx[ pWild-aName.getStr() ] = 0;
1290 0 : const char *pExt = strchr( pWild, '.' );
1291 0 : if ( pExt )
1292 : {
1293 0 : strncpy( ext, pExt, 4 );
1294 0 : ext[4] = 0;
1295 : }
1296 : else
1297 0 : strcpy( ext, ".tmp" );
1298 : }
1299 : else
1300 : {
1301 40 : aDirName = rtl::OUStringToOString(GetFull(), osl_getThreadTextEncoding());
1302 40 : strcpy( pfx, "lo" );
1303 40 : strcpy( ext, ".tmp" );
1304 : }
1305 40 : dir = aDirName.getStr();
1306 :
1307 : char sBuf[_MAX_PATH];
1308 40 : if ( eFlag == FSYS_FLAG_CURRENT || ( !pParent && pWild ) )
1309 0 : dir = TempDirImpl(sBuf);
1310 :
1311 40 : DirEntry aRet(FSYS_FLAG_INVALID);
1312 40 : i = strlen(dir);
1313 : // need to add ?\\? + prefix + number + pid + .ext + '\0'
1314 : # define TMPNAME_SIZE ( 1 + 5 + 5 + 10 + 4 + 1 )
1315 40 : ret_val = new char[i + TMPNAME_SIZE ];
1316 40 : if (ret_val)
1317 : {
1318 40 : strcpy(ret_val,dir);
1319 :
1320 : /* Make sure directory ends with a separator */
1321 : #if defined(WNT)
1322 : if ( i>0 && ret_val[i-1] != '\\' && ret_val[i-1] != '/' &&
1323 : ret_val[i-1] != ':')
1324 : ret_val[i++] = '\\';
1325 : #elif defined UNX
1326 40 : if (i>0 && ret_val[i-1] != '/')
1327 40 : ret_val[i++] = '/';
1328 : #else
1329 : #error unknown operating system
1330 : #endif
1331 :
1332 40 : strncpy(ret_val + i, pfx, 5);
1333 40 : ret_val[i + 5] = '\0'; /* strncpy doesn't put a 0 if more */
1334 40 : i = strlen(ret_val); /* than 'n' chars. */
1335 :
1336 : /* Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576
1337 : * Welcome to the 21st century, we can have longer filenames now ;)
1338 : * New format: pfx + "5 char milli/micro second res" + "current pid" + ".tmp"
1339 : */
1340 : #if (defined MSC || defined __MINGW32__) && defined WNT
1341 : /* Milliseconds !! */
1342 : static unsigned long u = GetTickCount();
1343 : unsigned long mypid = static_cast<unsigned long>(_getpid());
1344 : #else
1345 : /* Microseconds !! */
1346 40 : static unsigned long u = clock();
1347 40 : unsigned long mypid = static_cast<unsigned long>(getpid());
1348 : #endif
1349 80 : for ( unsigned long nOld = u; ++u != nOld; ) /* Hae??? */
1350 : {
1351 40 : u %= 100000; /* on *NIX repeats every 100ms, maybe less if CLOCKS_PER_SEC > 10^6 */
1352 40 : snprintf(ret_val+i, TMPNAME_SIZE, "%05lu%lu", u, mypid);
1353 :
1354 40 : strcat(ret_val,ext);
1355 :
1356 40 : if ( FSYS_KIND_FILE == eKind )
1357 : {
1358 0 : SvFileStream aStream( String( ret_val, osl_getThreadTextEncoding()),
1359 0 : STREAM_WRITE|STREAM_SHARE_DENYALL );
1360 0 : if ( aStream.IsOpen() )
1361 : {
1362 0 : aStream.Seek( STREAM_SEEK_TO_END );
1363 0 : if ( 0 == aStream.Tell() )
1364 : {
1365 0 : aRet = DirEntry( String( ret_val, osl_getThreadTextEncoding()));
1366 : break;
1367 : }
1368 0 : aStream.Close();
1369 0 : }
1370 : }
1371 : else
1372 : {
1373 : // Redirect
1374 40 : String aRetVal(ret_val, osl_getThreadTextEncoding());
1375 40 : String aRedirected (aRetVal);
1376 40 : if ( FSYS_KIND_DIR == eKind )
1377 : {
1378 0 : if (0 == _mkdir(rtl::OUStringToOString(aRedirected, osl_getThreadTextEncoding()).getStr()))
1379 : {
1380 0 : aRet = DirEntry( aRetVal );
1381 : break;
1382 : }
1383 : }
1384 : else
1385 : {
1386 : #if defined(UNX)
1387 40 : if (access(rtl::OUStringToOString(aRedirected, osl_getThreadTextEncoding()).getStr(), F_OK))
1388 : {
1389 40 : aRet = DirEntry( aRetVal );
1390 : break;
1391 : }
1392 : #else
1393 : struct stat aStat;
1394 : if (stat(rtl::OUStringToOString(aRedirected, osl_getThreadTextEncoding()).getStr(), &aStat))
1395 : {
1396 : aRet = DirEntry( aRetVal );
1397 : break;
1398 : }
1399 : #endif
1400 40 : }
1401 : }
1402 : }
1403 :
1404 40 : delete[] ret_val;
1405 40 : ret_val = 0;
1406 : }
1407 :
1408 40 : return aRet;
1409 : }
1410 :
1411 0 : const DirEntry &DirEntry::operator[]( sal_uInt16 nParentLevel ) const
1412 : {
1413 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1414 :
1415 : //TPF: maybe to be implemented (FastFSys)
1416 :
1417 0 : const DirEntry *pRes = this;
1418 0 : while ( pRes && nParentLevel-- )
1419 0 : pRes = pRes->pParent;
1420 :
1421 0 : return *pRes;
1422 : }
1423 :
1424 0 : sal_Bool DirEntry::MakeDir( sal_Bool bSloppy ) const
1425 : {
1426 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1427 :
1428 : // fast check if exists
1429 0 : if ( FileStat( *this ).IsKind( FSYS_KIND_DIR ) )
1430 0 : return sal_True;
1431 0 : if ( bSloppy && pParent )
1432 0 : if ( FileStat( *pParent ).IsKind( FSYS_KIND_DIR ) )
1433 0 : return sal_True;
1434 :
1435 0 : const DirEntry *pNewDir = bSloppy ? pParent : this;
1436 0 : if ( pNewDir )
1437 : {
1438 : // Create path to dir
1439 0 : if ( pNewDir->pParent && !pNewDir->pParent->MakeDir(sal_False) )
1440 0 : return sal_False;
1441 :
1442 : // create dir ourselves
1443 0 : if ( pNewDir->eFlag == FSYS_FLAG_ABSROOT ||
1444 : pNewDir->eFlag == FSYS_FLAG_VOLUME )
1445 0 : return sal_True;
1446 : else
1447 : {
1448 : //? nError = ???
1449 0 : if ( FileStat( *pNewDir ).IsKind( FSYS_KIND_DIR ) )
1450 0 : return sal_True;
1451 : else
1452 : {
1453 : FSysFailOnErrorImpl();
1454 0 : String aDirName(pNewDir->GetFull());
1455 0 : rtl::OString bDirName(rtl::OUStringToOString(aDirName, osl_getThreadTextEncoding()));
1456 :
1457 : #ifdef WIN32
1458 : SetLastError(0);
1459 : #endif
1460 0 : sal_Bool bResult = (0 == _mkdir(bDirName.getStr()));
1461 0 : if ( !bResult )
1462 : {
1463 : #ifdef WIN32
1464 : ((DirEntry *)this)->SetError( Sys2SolarError_Impl( GetLastError() ) );
1465 : #else
1466 0 : ((DirEntry *)this)->SetError( Sys2SolarError_Impl( errno ) );
1467 : #endif
1468 : }
1469 :
1470 0 : return bResult;
1471 : }
1472 : }
1473 : }
1474 0 : return sal_True;
1475 : }
1476 :
1477 630 : FSysError DirEntry::CopyTo( const DirEntry& rDest, FSysAction nActions ) const
1478 : {
1479 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1480 :
1481 630 : if ( FSYS_ACTION_COPYFILE != (nActions & FSYS_ACTION_COPYFILE) )
1482 : #ifdef UNX
1483 : {
1484 : // create hardlink
1485 : // redirection missing
1486 0 : rtl::OString aThis(rtl::OUStringToOString(GetFull(), osl_getThreadTextEncoding()));
1487 0 : rtl::OString aDest(rtl::OUStringToOString(rDest.GetFull(), osl_getThreadTextEncoding()));
1488 0 : if (link(aThis.getStr(), aDest.getStr()) == -1)
1489 0 : return Sys2SolarError_Impl( errno );
1490 : else
1491 0 : return FSYS_ERR_OK;
1492 : }
1493 : #else
1494 : return FSYS_ERR_NOTSUPPORTED;
1495 : #endif
1496 :
1497 630 : FileCopier fc(*this, rDest);
1498 630 : return fc.Execute(nActions);
1499 : }
1500 :
1501 : #if defined WNT || defined UNX
1502 40 : FSysError DirEntry::MoveTo( const DirEntry& rNewName ) const
1503 : {
1504 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1505 :
1506 40 : DirEntry aDest(rNewName);
1507 40 : FileStat aDestStat(rNewName);
1508 40 : if ( aDestStat.IsKind(FSYS_KIND_DIR ) )
1509 : {
1510 0 : aDest += DirEntry(rtl::OStringToOUString(aName, osl_getThreadTextEncoding()));
1511 : }
1512 40 : if ( aDest.Exists() )
1513 : {
1514 0 : return FSYS_ERR_ALREADYEXISTS;
1515 : }
1516 :
1517 : FSysFailOnErrorImpl();
1518 40 : String aFrom( GetFull() );
1519 :
1520 40 : String aTo( aDest.GetFull() );
1521 :
1522 40 : rtl::OString bFrom(rtl::OUStringToOString(aFrom, osl_getThreadTextEncoding()));
1523 40 : rtl::OString bTo(rtl::OUStringToOString(aTo, osl_getThreadTextEncoding()));
1524 :
1525 : #ifdef WNT
1526 : // MoveTo nun atomar
1527 : SetLastError(0);
1528 :
1529 : DirEntry aFromDevice(rtl::OStringToOUString(bFrom, osl_getThreadTextEncoding()));
1530 : DirEntry aToDevice(rtl::OStringToOUString(bTo,osl_getThreadTextEncoding()));
1531 : aFromDevice.ToAbs();
1532 : aToDevice.ToAbs();
1533 : aFromDevice=aFromDevice.GetDevice();
1534 : aToDevice=aToDevice.GetDevice();
1535 :
1536 : if (aFromDevice==aToDevice)
1537 : {
1538 : // same device, use intra-device-move with MoveFile
1539 : MoveFile( bFrom.getStr(), bTo.getStr() );
1540 : // Note: MoveFile is buggy for cross-device operations.
1541 : // Return value is TRUE, even if the operation was only partially successful.
1542 : // MoveFile has varying behavior between differing NT-versions.
1543 : return Sys2SolarError_Impl( GetLastError() );
1544 : }
1545 : else
1546 : {
1547 : // Not the same device, use inter-device-move with copy/delete
1548 : FSysError nCopyError = CopyTo(rNewName, FSYS_ACTION_COPYFILE);
1549 :
1550 : DirEntry aKill(rtl::OStringToOUString(bTo, osl_getThreadTextEncoding()));
1551 : FileStat aKillStat(String(rtl::OStringToOUString(bTo, osl_getThreadTextEncoding())));
1552 : if ( aKillStat.IsKind(FSYS_KIND_DIR ) )
1553 : {
1554 : aKill += String(rtl::OStringToOUString(aName, osl_getThreadTextEncoding()));
1555 : }
1556 :
1557 : if (nCopyError==FSYS_ERR_OK)
1558 : {
1559 : if (Kill()==FSYS_ERR_OK)
1560 : {
1561 : return FSYS_ERR_OK;
1562 : }
1563 : else
1564 : {
1565 : aKill.Kill();
1566 : return FSYS_ERR_ACCESSDENIED;
1567 : }
1568 : }
1569 : else
1570 : {
1571 : aKill.Kill();
1572 : return nCopyError;
1573 : }
1574 : }
1575 : #else
1576 : // #68639#
1577 : // on some nfs connections rename with from == to
1578 : // leads to destruction of file
1579 40 : if ( ( aFrom != aTo ) && ( 0 != rename( bFrom.getStr(), bTo.getStr() ) ) )
1580 : #if !defined(UNX)
1581 : return Sys2SolarError_Impl( GetLastError() );
1582 : #else
1583 : {
1584 0 : if( errno == EXDEV )
1585 : // simple rename does not work cross device
1586 : {
1587 0 : FILE *fpIN = fopen( bFrom.getStr(), "r" );
1588 0 : FILE *fpOUT = fopen( bTo.getStr(), "w" );
1589 0 : if( fpIN && fpOUT )
1590 : {
1591 : char pBuf[ 16384 ];
1592 0 : int nBytes, nWritten, nErr = 0;
1593 0 : errno = 0;
1594 0 : while( ( nBytes = fread( pBuf, 1, sizeof(pBuf), fpIN ) ) && ! nErr )
1595 : {
1596 0 : nWritten = fwrite( pBuf, 1, nBytes, fpOUT );
1597 : // Error in fwrite ?
1598 0 : if( nWritten < nBytes )
1599 : {
1600 0 : nErr = errno;
1601 0 : break;
1602 : }
1603 : }
1604 0 : fclose( fpIN );
1605 0 : fclose( fpOUT );
1606 0 : if ( nErr )
1607 : {
1608 0 : unlink( bTo.getStr() );
1609 0 : return Sys2SolarError_Impl( nErr );
1610 : }
1611 : else
1612 : {
1613 0 : unlink( bFrom.getStr() );
1614 0 : }
1615 : }
1616 : else
1617 : {
1618 0 : if ( fpIN )
1619 0 : fclose( fpIN );
1620 0 : if ( fpOUT )
1621 0 : fclose( fpOUT );
1622 0 : return Sys2SolarError_Impl( EXDEV );
1623 : }
1624 : }
1625 : else
1626 : {
1627 0 : return Sys2SolarError_Impl( errno );
1628 : }
1629 : }
1630 : #endif
1631 : #endif
1632 :
1633 : // For the WNT case we always return already above, so avoid warning
1634 : // C4702: unreachable code. Possibly also in non-WNT cases we always
1635 : // return already above, but gcc apparently doesn't mind.
1636 : #ifndef WNT
1637 40 : return ERRCODE_NONE;
1638 : #endif
1639 : }
1640 :
1641 : #endif
1642 :
1643 732 : FSysError DirEntry::Kill( FSysAction nActions ) const
1644 : {
1645 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1646 :
1647 732 : FSysError eError = FSYS_ERR_OK;
1648 : FSysFailOnErrorImpl();
1649 :
1650 : // Terminate name string with two '0'
1651 732 : String aTmpName( GetFull() );
1652 732 : rtl::OString bTmpName(rtl::OUStringToOString(aTmpName, osl_getThreadTextEncoding()));
1653 :
1654 732 : char *pName = new char[bTmpName.getLength()+2];
1655 732 : strcpy( pName, bTmpName.getStr() );
1656 732 : pName[bTmpName.getLength()+1] = (char) 0;
1657 :
1658 : // delete read-only files as well
1659 732 : sal_Bool isReadOnly = FileStat::GetReadOnlyFlag(*this);
1660 732 : if (isReadOnly)
1661 : {
1662 0 : FileStat::SetReadOnlyFlag(*this, sal_False);
1663 : }
1664 :
1665 : // directory?
1666 732 : if ( FileStat( *this ).IsKind(FSYS_KIND_DIR) )
1667 : {
1668 : // Delete recursively?
1669 0 : if ( FSYS_ACTION_RECURSIVE == (nActions & FSYS_ACTION_RECURSIVE) )
1670 : {
1671 0 : Dir aDir( *this, FSYS_KIND_DIR|FSYS_KIND_FILE );
1672 0 : for ( sal_uInt16 n = 0; eError == FSYS_ERR_OK && n < aDir.Count(); ++n )
1673 : {
1674 0 : const DirEntry &rSubDir = aDir[n];
1675 0 : DirEntryFlag flag = rSubDir.GetFlag();
1676 0 : if ( flag != FSYS_FLAG_CURRENT && flag != FSYS_FLAG_PARENT )
1677 0 : eError = rSubDir.Kill(nActions);
1678 0 : }
1679 : }
1680 :
1681 : // remove Dir myself
1682 : #ifdef WIN32
1683 : SetLastError(0);
1684 : #endif
1685 0 : if ( eError == FSYS_ERR_OK && 0 != _rmdir( (char*) pName ) )
1686 : {
1687 : // Change CWD if deletion failed
1688 : #ifdef WIN32
1689 : eError = Sys2SolarError_Impl( GetLastError() );
1690 : #else
1691 0 : eError = Sys2SolarError_Impl( errno );
1692 : #endif
1693 0 : if ( eError )
1694 : {
1695 0 : GetPath().SetCWD();
1696 : #ifdef WIN32
1697 : SetLastError(0);
1698 : #endif
1699 0 : if (_rmdir( (char*) pName) != 0)
1700 : {
1701 : #ifdef WIN32
1702 : eError = Sys2SolarError_Impl( GetLastError() );
1703 : #else
1704 0 : eError = Sys2SolarError_Impl( errno );
1705 : #endif
1706 : }
1707 : else
1708 : {
1709 0 : eError = FSYS_ERR_OK;
1710 : }
1711 : }
1712 : }
1713 : }
1714 : else
1715 : {
1716 732 : if ( FSYS_ACTION_USERECYCLEBIN == (nActions & FSYS_ACTION_USERECYCLEBIN) )
1717 : {
1718 : #if defined(WNT)
1719 : SHFILEOPSTRUCT aOp;
1720 : aOp.hwnd = 0;
1721 : aOp.wFunc = FO_DELETE;
1722 : aOp.pFrom = pName;
1723 : aOp.pTo = 0;
1724 : aOp.fFlags = FOF_ALLOWUNDO|FOF_SILENT|FOF_NOCONFIRMATION;
1725 : aOp.hNameMappings = 0;
1726 : aOp.lpszProgressTitle = 0;
1727 : eError = Sys2SolarError_Impl( SHFileOperation( &aOp ) );
1728 : #else
1729 0 : eError = ERRCODE_IO_NOTSUPPORTED;
1730 : #endif
1731 : }
1732 : else
1733 : {
1734 : #ifdef WIN32
1735 : SetLastError(0);
1736 : #endif
1737 732 : if ( 0 != _unlink( (char*) pName ) )
1738 : {
1739 : #ifdef WIN32
1740 : eError = Sys2SolarError_Impl( GetLastError() );
1741 : #else
1742 32 : eError = Sys2SolarError_Impl( errno );
1743 : #endif
1744 : }
1745 : else
1746 : {
1747 700 : eError = ERRCODE_NONE;
1748 : }
1749 : }
1750 : }
1751 :
1752 : // restore original read-only flag upon error
1753 732 : if ( isReadOnly && (eError!=ERRCODE_NONE) )
1754 : {
1755 0 : FileStat::SetReadOnlyFlag(*this, isReadOnly);
1756 : }
1757 :
1758 732 : delete[] pName;
1759 732 : return eError;
1760 : }
1761 :
1762 : /** Check if rSubEntry is (in)directly beneath *this */
1763 0 : sal_Bool DirEntry::Contains( const DirEntry &rSubEntry ) const
1764 : {
1765 : DBG_ASSERT( IsAbs() && rSubEntry.IsAbs(), "must be absolute entries" );
1766 :
1767 0 : sal_uInt16 nThisLevel = Level();
1768 0 : sal_uInt16 nSubLevel = rSubEntry.Level();
1769 0 : if ( nThisLevel < nSubLevel )
1770 : {
1771 0 : for ( ; nThisLevel; --nThisLevel, --nSubLevel )
1772 0 : if ( (*this)[nThisLevel-1] != rSubEntry[nSubLevel-1] )
1773 0 : return sal_False;
1774 0 : return sal_True;
1775 : }
1776 0 : return sal_False;
1777 : }
1778 :
1779 0 : sal_uInt16 DirEntry::Level() const
1780 : {
1781 : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1782 :
1783 0 : sal_uInt16 nLevel = 0;
1784 0 : const DirEntry *pRes = this;
1785 0 : while ( pRes )
1786 : {
1787 0 : pRes = pRes->pParent;
1788 0 : nLevel++;
1789 : }
1790 :
1791 0 : return nLevel;
1792 : }
1793 :
1794 231459 : sal_Bool DirEntry::IsValid() const
1795 : {
1796 231459 : return (nError == FSYS_ERR_OK);
1797 : }
1798 :
1799 : #if defined(DBG_UTIL)
1800 : void FSysTest()
1801 : {
1802 : }
1803 : #endif
1804 :
1805 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|