Branch data 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 : 0 : int Sys2SolarError_Impl( int nSysErr )
63 : : {
64 [ # # # # : 0 : 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 : 0 : 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 : 35542 : 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 : 234079 : inline void DirEntryStack::Push( DirEntry *pEntry )
131 : : {
132 : 234079 : maStack.push_back( pEntry );
133 : 234079 : }
134 : :
135 : 234079 : inline DirEntry* DirEntryStack::Pop()
136 : : {
137 : 234079 : DirEntry* pEntry = NULL;
138 [ + - ]: 234079 : if ( !maStack.empty() ) {
139 : 234079 : pEntry = maStack.back();
140 : 234079 : maStack.pop_back();
141 : : }
142 : 234079 : return pEntry;
143 : : }
144 : :
145 : 71084 : inline DirEntry* DirEntryStack::Top()
146 : : {
147 [ - + ]: 71084 : return maStack.empty() ? NULL : maStack.back();
148 : : }
149 : :
150 : : inline DirEntry* DirEntryStack::Bottom()
151 : : {
152 : : return maStack.empty() ? NULL : maStack.front();
153 : : }
154 : :
155 : 269621 : inline bool DirEntryStack::Empty()
156 : : {
157 : 269621 : return maStack.empty();
158 : : }
159 : :
160 : : inline void DirEntryStack::Clear()
161 : : {
162 : : maStack.clear();
163 : : }
164 : :
165 : : DBG_NAME( DirEntry );
166 : :
167 : 35542 : DirEntryStack::~DirEntryStack()
168 : : {
169 : 35542 : maStack.clear();
170 : 35542 : }
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 : 35542 : 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 [ + - ]: 35542 : DirEntryStack aStack;
412 : 35542 : rtl::OString aPfad(rPfad);
413 [ + + ]: 234079 : 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 [ + + + + ]: 3460383 : for ( nPos = 0;
[ + + ]
421 : 3226304 : nPos < aPfad.getLength() && aPfad[nPos] != '/';
422 : : nPos++ )
423 : : /* do nothing */;
424 : :
425 : : // is the name the root of the current drive?
426 [ + + ][ + - ]: 234079 : if ( nPos == 0 && !aPfad.isEmpty() && ( aPfad[0] == '/' ) )
[ + - ][ + + ]
427 : : {
428 : : // push root directory of current drive to stack
429 [ + - ][ + - ]: 24543 : aStack.Push( new DirEntry( FSYS_FLAG_ABSROOT ) );
[ + - ]
430 : : }
431 : : else
432 : : {
433 : : // split name without seperator
434 : 209536 : aName = aPfad.copy(0, nPos);
435 : :
436 : : // Is the name the current directory?
437 [ + - ]: 209536 : if ( aName == "." )
438 : : /* do nothing */;
439 : :
440 : : #ifdef UNX
441 : : // Is the name the user's home directory?
442 [ - + ]: 209536 : 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 [ - + ]: 209536 : 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 : 209536 : DirEntry *pNew = NULL;
471 : : // push ordinary entries on the stack
472 [ + - ][ + - ]: 209536 : pNew = new DirEntry( aName, FSYS_FLAG_NORMAL );
473 [ + - ][ - + ]: 209536 : if ( !pNew->IsValid() )
474 : : {
475 : 0 : aName = rPfad;
476 : 0 : ErrCode eErr = pNew->GetError();
477 [ # # ][ # # ]: 0 : delete pNew;
478 : 0 : return eErr;
479 : : }
480 [ + - ]: 209536 : aStack.Push( pNew );
481 : : }
482 : : }
483 : :
484 : : // get remainder of path
485 : 234079 : aPfad = nPos < aPfad.getLength()
486 [ + + ]: 234079 : ? aPfad.copy(nPos + 1) : rtl::OString();
487 [ + + ][ - + ]: 234079 : while ( !aPfad.isEmpty() && ( aPfad[0] == '/' ) )
[ - + ]
488 : 0 : aPfad = aPfad.copy(1);
489 : : }
490 : 234079 : while (!aPfad.isEmpty());
491 : :
492 : : // insert main entry itself
493 [ - + ]: 35542 : if ( aStack.Empty() )
494 : : {
495 : 0 : eFlag = FSYS_FLAG_CURRENT;
496 : 0 : aName = rtl::OString();
497 : : }
498 : : else
499 : : {
500 [ + - ]: 35542 : eFlag = aStack.Top()->eFlag;
501 [ + - ]: 35542 : aName = aStack.Top()->aName;
502 [ + - ][ + - ]: 35542 : delete aStack.Pop();
[ + - ]
503 : : }
504 : :
505 : : // Get parent entries from stack
506 : 35542 : DirEntry** pTemp = &pParent;
507 [ + + ]: 234079 : while ( !aStack.Empty() )
508 : : {
509 [ + - ]: 198537 : *pTemp = aStack.Pop();
510 : 198537 : pTemp = &( (*pTemp)->pParent );
511 : : }
512 : :
513 : 35542 : return FSYS_ERR_OK;
514 : : #endif
515 : : }
516 : :
517 : 527847 : static FSysPathStyle GetStyle( FSysPathStyle eStyle )
518 : : {
519 [ + + ][ - + ]: 527847 : if ( eStyle == FSYS_STYLE_HOST || eStyle == FSYS_STYLE_DETECT )
520 : 51617 : return DEFSTYLE;
521 : : else
522 : 527847 : return eStyle;
523 : : }
524 : :
525 : : /** Convert name to match OS norm. */
526 : 209536 : void DirEntry::ImpTrim()
527 : : {
528 : : // Do not trim wildcard characters
529 [ + - + - : 628608 : if ( ( aName.indexOf( '*' ) != -1 ) ||
- + ][ - + ]
530 : 209536 : ( aName.indexOf( '?' ) != -1 ) ||
531 : 209536 : ( aName.indexOf( ';' ) != -1 ) )
532 : 209536 : 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 [ - + ]: 209536 : 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 : 209536 : DirEntry::DirEntry( const rtl::OString& rName, DirEntryFlag eDirFlag ) :
550 : : #ifdef FEAT_FSYS_DOUBLESPEED
551 : : pStat( 0 ),
552 : : #endif
553 : 209536 : aName( rName )
554 : : {
555 : : DBG_CTOR( DirEntry, ImpCheckDirEntry );
556 : :
557 : 209536 : pParent = NULL;
558 : 209536 : eFlag = eDirFlag;
559 : 209536 : nError = FSYS_ERR_OK;
560 : :
561 [ + - ]: 209536 : ImpTrim();
562 : 209536 : }
563 : :
564 : 504759 : DirEntry::DirEntry( const DirEntry& rOrig ) :
565 : : #ifdef FEAT_FSYS_DOUBLESPEED
566 [ # # ]: 0 : pStat( rOrig.pStat ? new FileStat(*rOrig.pStat) : 0 ),
567 : : #endif
568 [ - + ]: 504759 : aName( rOrig.aName )
569 : : {
570 : : DBG_CTOR( DirEntry, ImpCheckDirEntry );
571 : :
572 : 504759 : eFlag = rOrig.eFlag;
573 : 504759 : nError = rOrig.nError;
574 : :
575 [ + + ]: 504759 : if ( rOrig.pParent )
576 : : {
577 [ + - ][ + - ]: 440212 : pParent = new DirEntry( *rOrig.pParent );
578 : : }
579 : : else
580 : : {
581 : 64547 : pParent = NULL;
582 : : }
583 : 504759 : }
584 : :
585 : 35542 : DirEntry::DirEntry( const String& rInitName, FSysPathStyle eStyle )
586 : : #ifdef FEAT_FSYS_DOUBLESPEED
587 : 35542 : : pStat( 0 )
588 : : #endif
589 : : {
590 : : DBG_CTOR( DirEntry, ImpCheckDirEntry );
591 : :
592 : : (void) eStyle; // only used for DBG_UTIL
593 : :
594 : 35542 : pParent = NULL;
595 : :
596 : : // faster check for empty string
597 [ - + ]: 35542 : if ( !rInitName.Len())
598 : : {
599 : 0 : eFlag = FSYS_FLAG_CURRENT;
600 : 0 : nError = FSYS_ERR_OK;
601 : 35542 : return;
602 : : }
603 : :
604 [ + - ][ + - ]: 35542 : rtl::OString aTmpName(rtl::OUStringToOString(rInitName, osl_getThreadTextEncoding()));
[ + - ]
605 [ - + ]: 35542 : 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 : 35542 : ::rtl::OUString aTmp;
616 : 35542 : ::rtl::OUString aOInitName;
617 [ + - ][ + - ]: 35542 : if ( FileBase::getFileURLFromSystemPath( OUString( rInitName ), aTmp ) == FileBase::E_None )
[ + - ]
618 : : {
619 [ + - ]: 35542 : aOInitName = OUString( rInitName );
620 [ + - ][ + - ]: 35542 : aTmpName = rtl::OUStringToOString(aOInitName, osl_getThreadTextEncoding());
621 : 35542 : }
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 [ + - ]: 35542 : nError = ImpParseName( aTmpName );
634 : :
635 [ - + ]: 35542 : if ( nError != FSYS_ERR_OK )
636 : 35542 : 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 : 25971 : DirEntry::DirEntry( DirEntryFlag eDirFlag )
686 : : #ifdef FEAT_FSYS_DOUBLESPEED
687 : 25971 : : pStat( 0 )
688 : : #endif
689 : : {
690 : : DBG_CTOR( DirEntry, ImpCheckDirEntry );
691 : :
692 : 25971 : eFlag = eDirFlag;
693 [ + + ]: 25971 : nError = ( eFlag == FSYS_FLAG_INVALID ) ? FSYS_ERR_UNKNOWN : FSYS_ERR_OK;
694 : 25971 : pParent = NULL;
695 : 25971 : }
696 : :
697 : 775808 : DirEntry::~DirEntry()
698 : : {
699 : : DBG_DTOR( DirEntry, ImpCheckDirEntry );
700 : :
701 [ + + ][ + - ]: 775808 : delete pParent;
702 : : #ifdef FEAT_FSYS_DOUBLESPEED
703 [ - + ][ # # ]: 775808 : delete pStat;
704 : : #endif
705 : :
706 : 775808 : }
707 : :
708 : 21340 : const DirEntry* DirEntry::ImpGetTopPtr() const
709 : : {
710 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
711 : :
712 : 21340 : const DirEntry *pTemp = this;
713 [ + + ]: 108531 : while ( pTemp->pParent )
714 : 87191 : pTemp = pTemp->pParent;
715 : :
716 : 21340 : return pTemp;
717 : : }
718 : :
719 : 11060 : DirEntry* DirEntry::ImpGetTopPtr()
720 : : {
721 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
722 : :
723 : 11060 : DirEntry *pTemp = this;
724 [ + + ]: 11853 : while ( pTemp->pParent )
725 : 793 : pTemp = pTemp->pParent;
726 : :
727 : 11060 : 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 : 1143 : sal_Bool DirEntry::Exists( FSysAccess nAccess ) const
748 : : {
749 [ + + ][ + - ]: 1143 : static osl::Mutex aLocalMutex;
[ + - ][ # # ]
750 [ + - ]: 1143 : osl::MutexGuard aGuard( aLocalMutex );
751 [ + - ][ - + ]: 1143 : 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 [ + - ][ + - ]: 1143 : DirEntryKind eKind = FileStat( *this, nAccess ).GetKind();
773 [ + + ]: 1143 : 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 [ + - ]: 1143 : 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 : 238706 : String DirEntry::GetFull( FSysPathStyle eStyle, sal_Bool bWithDelimiter,
817 : : sal_uInt16 nMaxChars ) const
818 : : {
819 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
820 : :
821 : 238706 : rtl::OStringBuffer aBuf;
822 : 238706 : eStyle = GetStyle( eStyle );
823 [ + + ]: 238706 : if ( pParent )
824 : : {
825 [ + + ][ + - ]: 237524 : if ( ( pParent->eFlag == FSYS_FLAG_ABSROOT ||
[ - + ]
826 : : pParent->eFlag == FSYS_FLAG_RELROOT ||
827 : : pParent->eFlag == FSYS_FLAG_VOLUME ) )
828 : : {
829 [ + - ][ + - ]: 31562 : aBuf.append(rtl::OUStringToOString(pParent->GetName( eStyle ), osl_getThreadTextEncoding()));
[ + - ][ + - ]
[ + - ][ + - ]
830 [ + - ][ + - ]: 31562 : aBuf.append(rtl::OUStringToOString(GetName( eStyle ), osl_getThreadTextEncoding()));
[ + - ][ + - ]
[ + - ][ + - ]
831 : : }
832 : : else
833 : : {
834 [ + - ][ + - ]: 205962 : aBuf.append(rtl::OUStringToOString(pParent->GetFull( eStyle ), osl_getThreadTextEncoding()));
[ + - ][ + - ]
[ + - ][ + - ]
835 [ - + ][ + - ]: 205962 : aBuf.append(ACCESSDELIM_C(eStyle));
836 [ + - ][ + - ]: 237524 : aBuf.append(rtl::OUStringToOString(GetName( eStyle ), osl_getThreadTextEncoding()));
[ + - ][ + - ]
[ + - ][ + - ]
837 : : }
838 : : }
839 : : else
840 : : {
841 [ + - ][ + - ]: 1182 : aBuf.append(rtl::OUStringToOString(GetName(eStyle), osl_getThreadTextEncoding()));
[ + - ][ + - ]
[ + - ][ + - ]
842 : : }
843 : :
844 : : //! Hack
845 [ - + ]: 238706 : if ( bWithDelimiter )
846 [ # # ][ # # ]: 0 : if ( aBuf[aBuf.getLength()-1] != ACCESSDELIM_C(eStyle) )
847 [ # # ][ # # ]: 0 : aBuf.append(ACCESSDELIM_C(eStyle));
848 : :
849 : 238706 : rtl::OString aRet = aBuf.makeStringAndClear();
850 : :
851 : : // HACK
852 [ - + ]: 238706 : if ( nMaxChars < STRING_MAXLEN )
853 [ # # ][ # # ]: 0 : aRet = ImplCutPath( aRet, nMaxChars, ACCESSDELIM_C(eStyle) );
854 : :
855 [ + - ][ + - ]: 238706 : 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 : 40 : 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 : 278538 : String DirEntry::GetName( FSysPathStyle eStyle ) const
908 : : {
909 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
910 : :
911 : 278538 : rtl::OStringBuffer aRet;
912 : 278538 : eStyle = GetStyle( eStyle );
913 : :
914 [ - + - + : 278538 : 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 [ + - ]: 31562 : aRet.append(aName);
923 [ - + ][ + - ]: 31562 : aRet.append(ACCESSDELIM_C(eStyle));
924 : 31562 : 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 [ + - ]: 720 : if ( aName.isEmpty() )
936 : : {
937 [ + - ]: 720 : aRet.append(ACTCURRENT(eStyle));
938 : 720 : break;
939 : : }
940 : :
941 : : default:
942 [ + - ]: 246256 : aRet.append(aName);
943 : 246256 : break;
944 : : }
945 : :
946 : : return rtl::OStringToOUString(aRet.makeStringAndClear(),
947 [ + - ][ + - ]: 278538 : osl_getThreadTextEncoding());
[ + - ]
948 : : }
949 : :
950 : 112709 : bool DirEntry::IsAbs() const
951 : : {
952 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
953 : :
954 : : #ifdef UNX
955 [ + + ]: 112709 : 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 : 660 : 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 [ - + ][ # # ]: 660 : if ( nError && ( nError == rEntry.nError ) )
1004 : 0 : return sal_True;
1005 [ + - ][ + - ]: 660 : if ( nError || rEntry.nError ||
[ + - ][ - + ]
1006 : : ( eFlag == FSYS_FLAG_INVALID ) ||
1007 : : ( rEntry.eFlag == FSYS_FLAG_INVALID ) )
1008 : 0 : return sal_False;
1009 : :
1010 : 660 : const DirEntry *pThis = (DirEntry *)this;
1011 : 660 : const DirEntry *pWith = (DirEntry *)&rEntry;
1012 [ + - ][ + - ]: 660 : while( pThis && pWith && (pThis->eFlag == pWith->eFlag) )
[ + - ][ + - ]
1013 : : {
1014 [ + - ]: 660 : if ( CMP_LOWER(pThis->aName) != CMP_LOWER(pWith->aName) )
1015 : 660 : break;
1016 : 0 : pThis = pThis->pParent;
1017 : 0 : pWith = pWith->pParent;
1018 : : }
1019 : :
1020 [ - + ][ # # ]: 660 : return ( !pThis && !pWith );
1021 : : }
1022 : :
1023 : 11699 : DirEntry& DirEntry::operator=( const DirEntry& rEntry )
1024 : : {
1025 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1026 : :
1027 [ - + ]: 11699 : if ( this == &rEntry )
1028 : 0 : return *this;
1029 [ - + ]: 11699 : 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 : 11699 : aName = rEntry.aName;
1037 : 11699 : eFlag = rEntry.eFlag;
1038 : 11699 : nError = FSYS_ERR_OK;
1039 : :
1040 : 11699 : DirEntry *pOldParent = pParent;
1041 [ + - ]: 11699 : if ( rEntry.pParent )
1042 [ + - ]: 11699 : pParent = new DirEntry( *rEntry.pParent );
1043 : : else
1044 : 0 : pParent = NULL;
1045 : :
1046 [ + + ]: 11699 : if ( pOldParent )
1047 [ + - ]: 10878 : delete pOldParent;
1048 : 11699 : return *this;
1049 : : }
1050 : :
1051 : 10670 : 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 : 10670 : const DirEntry *pEntryTop = rEntry.ImpGetTopPtr();
1064 : 10670 : const DirEntry *pThisTop = ImpGetTopPtr();
1065 : :
1066 [ # # # # ]: 21340 : if (
[ + - ][ + - ]
[ - + ][ - + ]
[ - + # #
- + ]
1067 : 0 : (eFlag == FSYS_FLAG_RELROOT && aName.isEmpty()) ||
1068 : : (
1069 : 10670 : (!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 [ - + ][ # # ]: 10670 : 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 [ - + ][ # # ]: 10670 : 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 [ - + ]: 10670 : 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 [ + - ][ - + ]: 10670 : 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 [ + - ]: 10670 : DirEntry aRet( rEntry );
1116 : 10670 : DirEntry *pTop = aRet.ImpGetTopPtr();
1117 [ + - ][ + - ]: 10670 : pTop->pParent = new DirEntry( *this );
1118 : :
1119 [ + - ][ + - ]: 10670 : return aRet;
1120 : : }
1121 : :
1122 : 10670 : DirEntry &DirEntry::operator+=( const DirEntry& rEntry )
1123 : : {
1124 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1125 : :
1126 [ + - ]: 10670 : return *this = *this + rEntry;
1127 : : }
1128 : :
1129 : 60 : String DirEntry::GetAccessDelimiter( FSysPathStyle eFormatter )
1130 : : {
1131 [ - + ][ + - ]: 60 : return rtl::OUString( ACCESSDELIM_C( GetStyle( eFormatter ) ) );
1132 : : }
1133 : :
1134 : 1440 : void DirEntry::SetExtension( const String& rExtension, char cSep )
1135 : : {
1136 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1137 : :
1138 : : // do not set extensions for drives
1139 [ - + ]: 1440 : if(eFlag == FSYS_FLAG_ABSROOT)
1140 : : {
1141 : 0 : nError = FSYS_ERR_NOTSUPPORTED;
1142 : 1440 : return;
1143 : : }
1144 : :
1145 [ + - ]: 1440 : rtl::OStringBuffer aBuf(aName);
1146 : :
1147 : : // search cSep within aName
1148 : 1440 : const sal_Char *p0 = aBuf.getStr();
1149 : 1440 : const sal_Char *p1 = p0 + aBuf.getLength() - 1;
1150 [ + + ][ + + ]: 7740 : while ( p1 >= p0 && *p1 != cSep )
[ + + ]
1151 : 6300 : p1--;
1152 [ + + ]: 1440 : if ( p1 >= p0 )
1153 : : {
1154 : : // found a cSep on position p1
1155 : :
1156 : : sal_Int32 n = static_cast<sal_Int32>(
1157 : 780 : p1 - p0 + 1 - ( rExtension.Len() ? 0 : 1 ));
1158 : :
1159 [ + - ]: 780 : aBuf.remove(n, aBuf.getLength()-n);
1160 : : }
1161 [ + - ]: 660 : else if ( rExtension.Len() )
1162 : : {
1163 : : // no cSep was found
1164 [ + - ]: 660 : aBuf.append(cSep);
1165 : : }
1166 : :
1167 : : aBuf.append(rtl::OUStringToOString(rExtension,
1168 [ + - ][ + - ]: 1440 : osl_getThreadTextEncoding()));
[ + - ][ + - ]
1169 : :
1170 : 1440 : 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 : 390 : sal_Bool DirEntry::Find( const String& rPfad, char cDelim )
1194 : : {
1195 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1196 : :
1197 [ + + ]: 390 : if ( ImpGetTopPtr()->eFlag == FSYS_FLAG_ABSROOT )
1198 : 61 : 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 [ + - ]: 1143 : 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 : 1143 : return sal_True;
1229 [ + - ][ + + ]: 1143 : }
1230 [ + + ]: 1143 : }
1231 : : }
1232 : : while ( nIndex >= 0 );
1233 : 390 : 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 : 10543 : String DirEntry::GetSearchDelimiter( FSysPathStyle eFormatter )
1252 : : {
1253 [ + - ][ + - ]: 10543 : 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 [ + - ]: 40 : 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 : 660 : FSysError DirEntry::CopyTo( const DirEntry& rDest, FSysAction nActions ) const
1478 : : {
1479 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1480 : :
1481 [ - + ]: 660 : if ( FSYS_ACTION_COPYFILE != (nActions & FSYS_ACTION_COPYFILE) )
1482 : : #ifdef UNX
1483 : : {
1484 : : // create hardlink
1485 : : HACK(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 [ + - ]: 660 : FileCopier fc(*this, rDest);
1498 [ + - ][ + - ]: 660 : return fc.Execute(nActions);
1499 : : }
1500 : :
1501 : : #if defined WNT || defined UNX
1502 : 0 : FSysError DirEntry::MoveTo( const DirEntry& rNewName ) const
1503 : : {
1504 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1505 : :
1506 [ # # ]: 0 : DirEntry aDest(rNewName);
1507 [ # # ]: 0 : FileStat aDestStat(rNewName);
1508 [ # # ][ # # ]: 0 : if ( aDestStat.IsKind(FSYS_KIND_DIR ) )
1509 : : {
1510 [ # # ][ # # ]: 0 : aDest += DirEntry(rtl::OStringToOUString(aName, osl_getThreadTextEncoding()));
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1511 : : }
1512 [ # # ][ # # ]: 0 : if ( aDest.Exists() )
1513 : : {
1514 : 0 : return FSYS_ERR_ALREADYEXISTS;
1515 : : }
1516 : :
1517 : : FSysFailOnErrorImpl();
1518 [ # # ]: 0 : String aFrom( GetFull() );
1519 : :
1520 [ # # ]: 0 : String aTo( aDest.GetFull() );
1521 : :
1522 [ # # ][ # # ]: 0 : rtl::OString bFrom(rtl::OUStringToOString(aFrom, osl_getThreadTextEncoding()));
[ # # ]
1523 [ # # ][ # # ]: 0 : 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 [ # # ][ # # ]: 0 : 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 [ # # ][ # # ]: 0 : return ERRCODE_NONE;
[ # # ][ # # ]
1638 : : #endif
1639 : : }
1640 : :
1641 : : #endif
1642 : :
1643 : 761 : FSysError DirEntry::Kill( FSysAction nActions ) const
1644 : : {
1645 : : DBG_CHKTHIS( DirEntry, ImpCheckDirEntry );
1646 : :
1647 : 761 : FSysError eError = FSYS_ERR_OK;
1648 : : FSysFailOnErrorImpl();
1649 : :
1650 : : // Terminate name string with two '0'
1651 [ + - ]: 761 : String aTmpName( GetFull() );
1652 [ + - ][ + - ]: 761 : rtl::OString bTmpName(rtl::OUStringToOString(aTmpName, osl_getThreadTextEncoding()));
[ + - ]
1653 : :
1654 [ + - ]: 761 : char *pName = new char[bTmpName.getLength()+2];
1655 : 761 : strcpy( pName, bTmpName.getStr() );
1656 : 761 : pName[bTmpName.getLength()+1] = (char) 0;
1657 : :
1658 : : // delete read-only files as well
1659 [ + - ]: 761 : sal_Bool isReadOnly = FileStat::GetReadOnlyFlag(*this);
1660 [ - + ]: 761 : if (isReadOnly)
1661 : : {
1662 [ # # ]: 0 : FileStat::SetReadOnlyFlag(*this, sal_False);
1663 : : }
1664 : :
1665 : : // directory?
1666 [ + - ][ + - ]: 761 : 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 [ - + ]: 761 : 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 [ - + ]: 761 : if ( 0 != _unlink( (char*) pName ) )
1738 : : {
1739 : : #ifdef WIN32
1740 : : eError = Sys2SolarError_Impl( GetLastError() );
1741 : : #else
1742 [ # # ]: 0 : eError = Sys2SolarError_Impl( errno );
1743 : : #endif
1744 : : }
1745 : : else
1746 : : {
1747 : 761 : eError = ERRCODE_NONE;
1748 : : }
1749 : : }
1750 : : }
1751 : :
1752 : : // restore original read-only flag upon error
1753 [ - + ][ # # ]: 761 : if ( isReadOnly && (eError!=ERRCODE_NONE) )
1754 : : {
1755 [ # # ]: 0 : FileStat::SetReadOnlyFlag(*this, isReadOnly);
1756 : : }
1757 : :
1758 [ + - ]: 761 : delete[] pName;
1759 [ + - ]: 761 : 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 : 223622 : sal_Bool DirEntry::IsValid() const
1795 : : {
1796 : 223622 : 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: */
|