xref: /trunk/main/sal/osl/unx/file_misc.cxx (revision cf6516809c57e1bb0a940545cca99cdad54d4ce2)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "osl/file.hxx"
25 
26 #include "osl/diagnose.h"
27 #include "osl/thread.h"
28 #include <osl/signal.h>
29 #include "rtl/alloc.h"
30 
31 #include "system.h"
32 #include "file_impl.hxx"
33 #include "file_error_transl.h"
34 #include "file_path_helper.hxx"
35 #include "file_url.h"
36 #include "uunxapi.hxx"
37 
38 #include <sys/types.h>
39 #include <errno.h>
40 #include <dirent.h>
41 #include <limits.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <sys/stat.h>
46 #include <sys/mman.h>
47 
48 #include <algorithm>
49 
50 /************************************************************************
51  *   ToDo
52  *
53  *   - Fix: check for corresponding struct sizes in exported functions
54  *   - check size/use of oslDirectory
55  *   - check size/use of oslDirectoryItem
56  ***********************************************************************/
57 /******************************************************************************
58  * Data Type Definition
59  ******************************************************************************/
60 
61 typedef struct
62 {
63     rtl_uString* ustrPath; /* holds native directory path */
64     DIR*         pDirStruct;
65 } oslDirectoryImpl;
66 
67 #if 0
68 /* FIXME: reintroducing this may save some extra bytes per Item */
69 typedef struct
70 {
71     rtl_uString* ustrFileName; /* holds native file name */
72     rtl_uString* ustrDirPath; /* holds native dir path */
73     sal_uInt32   RefCount;
74 } oslDirectoryItemImpl;
75 #endif
76 
77 DirectoryItem_Impl::DirectoryItem_Impl(
78     rtl_uString * ustrFilePath, unsigned char DType)
79     : m_RefCount     (1),
80       m_ustrFilePath (ustrFilePath),
81       m_DType        (DType)
82 {
83     if (m_ustrFilePath != 0)
84         rtl_uString_acquire(m_ustrFilePath);
85 }
86 DirectoryItem_Impl::~DirectoryItem_Impl()
87 {
88     if (m_ustrFilePath != 0)
89         rtl_uString_release(m_ustrFilePath);
90 }
91 
92 void * DirectoryItem_Impl::operator new(size_t n)
93 {
94     return rtl_allocateMemory(n);
95 }
96 void DirectoryItem_Impl::operator delete(void * p, size_t)
97 {
98     rtl_freeMemory(p);
99 }
100 
101 void DirectoryItem_Impl::acquire()
102 {
103     ++m_RefCount;
104 }
105 void DirectoryItem_Impl::release()
106 {
107     if (0 == --m_RefCount)
108         delete this;
109 }
110 
111 oslFileType DirectoryItem_Impl::getFileType() const
112 {
113     switch (m_DType)
114     {
115 #ifdef _DIRENT_HAVE_D_TYPE
116         case DT_LNK:
117             return osl_File_Type_Link;
118         case DT_DIR:
119             return osl_File_Type_Directory;
120         case DT_REG:
121             return osl_File_Type_Regular;
122         case DT_FIFO:
123             return osl_File_Type_Fifo;
124         case DT_SOCK:
125             return osl_File_Type_Socket;
126         case DT_CHR:
127         case DT_BLK:
128             return osl_File_Type_Special;
129 #endif /* _DIRENT_HAVE_D_TYPE */
130         default:
131             break;
132     }
133     return osl_File_Type_Unknown;
134 }
135 
136 /******************************************************************************
137  * C-String Function Declarations
138  *****************************************************************************/
139 
140 static oslFileError osl_psz_createDirectory(const sal_Char* pszPath);
141 static oslFileError osl_psz_removeDirectory(const sal_Char* pszPath);
142 
143 /*******************************************************************
144  * osl_openDirectory
145  ******************************************************************/
146 
147 oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirectory* pDirectory)
148 {
149     rtl_uString* ustrSystemPath = NULL;
150     oslFileError eRet;
151 
152     char path[PATH_MAX];
153 
154     if ((0 == ustrDirectoryURL) || (0 == ustrDirectoryURL->length) || (0 == pDirectory))
155         return osl_File_E_INVAL;
156 
157     /* convert file URL to system path */
158     eRet = osl_getSystemPathFromFileURL_Ex(ustrDirectoryURL, &ustrSystemPath, sal_False);
159 
160     if( osl_File_E_None != eRet )
161         return eRet;
162 
163     osl_systemPathRemoveSeparator(ustrSystemPath);
164 
165     /* convert unicode path to text */
166     if ( UnicodeToText( path, PATH_MAX, ustrSystemPath->buffer, ustrSystemPath->length )
167 #ifdef MACOSX
168      && macxp_resolveAlias( path, PATH_MAX ) == 0
169 #endif /* MACOSX */
170      )
171     {
172         /* open directory */
173         DIR *pdir = opendir( path );
174 
175         if( pdir )
176         {
177             /* create and initialize impl structure */
178             oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) );
179 
180             if( pDirImpl )
181             {
182                 pDirImpl->pDirStruct = pdir;
183                 pDirImpl->ustrPath = ustrSystemPath;
184 
185                 *pDirectory = (oslDirectory) pDirImpl;
186                 return osl_File_E_None;
187             }
188             else
189             {
190                 errno = ENOMEM;
191                 closedir( pdir );
192             }
193         }
194         else
195         {
196 #ifdef DEBUG_OSL_FILE
197             perror ("osl_openDirectory"); fprintf (stderr, path);
198 #endif
199         }
200     }
201 
202     rtl_uString_release( ustrSystemPath );
203 
204     return oslTranslateFileError(OSL_FET_ERROR, errno);
205 }
206 
207 /****************************************************************************/
208 /* osl_closeDirectory */
209 /****************************************************************************/
210 
211 oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory )
212 {
213     oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) Directory;
214     oslFileError err = osl_File_E_None;
215 
216     OSL_ASSERT( Directory );
217 
218     if( NULL == pDirImpl )
219         return osl_File_E_INVAL;
220 
221     /* close directory */
222     if( closedir( pDirImpl->pDirStruct ) )
223     {
224         err = oslTranslateFileError(OSL_FET_ERROR, errno);
225     }
226 
227     /* cleanup members */
228     rtl_uString_release( pDirImpl->ustrPath );
229 
230     rtl_freeMemory( pDirImpl );
231 
232     return err;
233 }
234 
235 /**********************************************
236  * osl_readdir_impl_
237  *
238  * readdir wrapper, filters out "." and ".."
239  * on request
240  *********************************************/
241 
242 static struct dirent* osl_readdir_impl_(DIR* pdir, sal_Bool bFilterLocalAndParentDir)
243 {
244     struct dirent* pdirent;
245 
246     while ((pdirent = readdir(pdir)) != NULL)
247     {
248         if (bFilterLocalAndParentDir &&
249             ((0 == strcmp(pdirent->d_name, ".")) || (0 == strcmp(pdirent->d_name, ".."))))
250             continue;
251         else
252             break;
253     }
254 
255     return pdirent;
256 }
257 
258 /****************************************************************************
259  * osl_getNextDirectoryItem
260  ***************************************************************************/
261 
262 oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirectoryItem* pItem, sal_uInt32 /*uHint*/)
263 {
264     oslDirectoryImpl* pDirImpl     = (oslDirectoryImpl*)Directory;
265     rtl_uString*      ustrFileName = NULL;
266     rtl_uString*      ustrFilePath = NULL;
267     struct dirent*    pEntry;
268 
269     OSL_ASSERT(Directory);
270     OSL_ASSERT(pItem);
271 
272     if ((NULL == Directory) || (NULL == pItem))
273         return osl_File_E_INVAL;
274 
275     pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, sal_True);
276 
277     if (NULL == pEntry)
278         return osl_File_E_NOENT;
279 
280 
281 #if defined(MACOSX)
282 
283     // convert decomposed filename to precomposed unicode
284     char composed_name[BUFSIZ];
285     CFMutableStringRef strRef = CFStringCreateMutable (NULL, 0 );
286     CFStringAppendCString( strRef, pEntry->d_name, kCFStringEncodingUTF8 ); //UTF8 is default on Mac OSX
287     CFStringNormalize( strRef, kCFStringNormalizationFormC );
288     CFStringGetCString( strRef, composed_name, BUFSIZ, kCFStringEncodingUTF8 );
289     CFRelease( strRef );
290     rtl_string2UString( &ustrFileName, composed_name, strlen( composed_name),
291     osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
292 
293 #else // not MACOSX
294     /* convert file name to unicode */
295     rtl_string2UString( &ustrFileName, pEntry->d_name, strlen( pEntry->d_name ),
296         osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
297     OSL_ASSERT(ustrFileName != 0);
298 
299 #endif
300 
301     osl_systemPathMakeAbsolutePath(pDirImpl->ustrPath, ustrFileName, &ustrFilePath);
302     rtl_uString_release( ustrFileName );
303 
304     DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(*pItem);
305     if (0 != pImpl)
306     {
307         pImpl->release(), pImpl = 0;
308     }
309 #ifdef _DIRENT_HAVE_D_TYPE
310     pImpl = new DirectoryItem_Impl(ustrFilePath, pEntry->d_type);
311 #else
312     pImpl = new DirectoryItem_Impl(ustrFilePath);
313 #endif /* _DIRENT_HAVE_D_TYPE */
314     *pItem = pImpl;
315     rtl_uString_release( ustrFilePath );
316 
317     return osl_File_E_None;
318 }
319 
320 /****************************************************************************/
321 /* osl_getDirectoryItem */
322 /****************************************************************************/
323 
324 oslFileError SAL_CALL osl_getDirectoryItem( rtl_uString* ustrFileURL, oslDirectoryItem* pItem )
325 {
326     rtl_uString* ustrSystemPath = NULL;
327     oslFileError osl_error      = osl_File_E_INVAL;
328 
329     OSL_ASSERT((0 != ustrFileURL) && (0 != pItem));
330     if ((0 == ustrFileURL) || (0 == ustrFileURL->length) || (0 == pItem))
331         return osl_File_E_INVAL;
332 
333     osl_error = osl_getSystemPathFromFileURL_Ex(ustrFileURL, &ustrSystemPath, sal_False);
334     if (osl_File_E_None != osl_error)
335         return osl_error;
336 
337     osl_systemPathRemoveSeparator(ustrSystemPath);
338 
339     if (-1 == access_u(ustrSystemPath, F_OK))
340     {
341         osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
342     }
343     else
344     {
345         *pItem = new DirectoryItem_Impl(ustrSystemPath);
346     }
347     rtl_uString_release(ustrSystemPath);
348 
349     return osl_error;
350 }
351 
352 
353 /****************************************************************************/
354 /* osl_acquireDirectoryItem */
355 /****************************************************************************/
356 
357 oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item )
358 {
359     DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
360     if (0 == pImpl)
361         return osl_File_E_INVAL;
362 
363     pImpl->acquire();
364     return osl_File_E_None;
365 }
366 
367 /****************************************************************************/
368 /* osl_releaseDirectoryItem */
369 /****************************************************************************/
370 
371 oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
372 {
373     DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item);
374     if (0 == pImpl)
375         return osl_File_E_INVAL;
376 
377     pImpl->release();
378     return osl_File_E_None;
379 }
380 
381 /****************************************************************************/
382 /* osl_createDirectory */
383 /****************************************************************************/
384 
385 oslFileError SAL_CALL osl_createDirectory( rtl_uString* ustrDirectoryURL )
386 {
387     char path[PATH_MAX];
388     oslFileError eRet;
389 
390     OSL_ASSERT( ustrDirectoryURL );
391 
392     /* convert directory url to system path */
393     eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
394     if( eRet != osl_File_E_None )
395         return eRet;
396 
397 #ifdef MACOSX
398     if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
399         return oslTranslateFileError( OSL_FET_ERROR, errno );
400 #endif/* MACOSX */
401 
402     return osl_psz_createDirectory( path );
403 }
404 
405 /****************************************************************************/
406 /* osl_removeDirectory */
407 /****************************************************************************/
408 
409 oslFileError SAL_CALL osl_removeDirectory( rtl_uString* ustrDirectoryURL )
410 {
411     char path[PATH_MAX];
412     oslFileError eRet;
413 
414     OSL_ASSERT( ustrDirectoryURL );
415 
416     /* convert directory url to system path */
417     eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
418     if( eRet != osl_File_E_None )
419         return eRet;
420 
421 #ifdef MACOSX
422     if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
423         return oslTranslateFileError( OSL_FET_ERROR, errno );
424 #endif/* MACOSX */
425 
426     return osl_psz_removeDirectory( path );
427 }
428 
429 /*****************************************
430  * osl_psz_createDirectory
431  ****************************************/
432 
433 static oslFileError osl_psz_createDirectory( const sal_Char* pszPath )
434 {
435     int nRet=0;
436     int mode = S_IRWXU | S_IRWXG | S_IRWXO;
437 
438     nRet = mkdir(pszPath,mode);
439 
440     if ( nRet < 0 )
441     {
442         nRet=errno;
443         return oslTranslateFileError(OSL_FET_ERROR, nRet);
444     }
445 
446     return osl_File_E_None;
447 }
448 
449 /*****************************************
450  * osl_psz_removeDirectory
451  ****************************************/
452 
453 static oslFileError osl_psz_removeDirectory( const sal_Char* pszPath )
454 {
455     int nRet=0;
456 
457     nRet = rmdir(pszPath);
458 
459     if ( nRet < 0 )
460     {
461         nRet=errno;
462         return oslTranslateFileError(OSL_FET_ERROR, nRet);
463     }
464 
465     return osl_File_E_None;
466 }
467 
468 /****************************************************************************/
469 /* osl_createDirectoryPath */
470 /****************************************************************************/
471 
472 static int path_make_parent(sal_Unicode* path)
473 {
474     int i = rtl_ustr_lastIndexOfChar(path, '/');
475 
476     if (i > 0)
477     {
478         *(path + i) = 0;
479         return i;
480     }
481     else
482         return 0;
483 }
484 
485 static int create_dir_with_callback(
486     sal_Unicode* directory_path,
487     oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
488     void* pData)
489 {
490     int mode = S_IRWXU | S_IRWXG | S_IRWXO;
491 
492     if (osl::mkdir(directory_path, mode) == 0)
493     {
494         if (aDirectoryCreationCallbackFunc)
495         {
496             rtl::OUString url;
497             osl::FileBase::getFileURLFromSystemPath(directory_path, url);
498             aDirectoryCreationCallbackFunc(pData, url.pData);
499         }
500         return 0;
501     }
502     return errno;
503 }
504 
505 static oslFileError create_dir_recursively_(
506     sal_Unicode* dir_path,
507     oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
508     void* pData)
509 {
510     OSL_PRECOND((rtl_ustr_getLength(dir_path) > 0) && ((dir_path + (rtl_ustr_getLength(dir_path) - 1)) != (dir_path + rtl_ustr_lastIndexOfChar(dir_path, '/'))), \
511     "Path must not end with a slash");
512 
513     int native_err = create_dir_with_callback(
514         dir_path, aDirectoryCreationCallbackFunc, pData);
515 
516     if (native_err == 0)
517         return osl_File_E_None;
518 
519     if (native_err != ENOENT)
520         return oslTranslateFileError(OSL_FET_ERROR, native_err);
521 
522     // we step back until '/a_dir' at maximum because
523     // we should get an error unequal ENOENT when
524     // we try to create 'a_dir' at '/' and would so
525     // return before
526     int pos = path_make_parent(dir_path);
527 
528     oslFileError osl_error = create_dir_recursively_(
529         dir_path, aDirectoryCreationCallbackFunc, pData);
530 
531     if (osl_File_E_None != osl_error)
532         return osl_error;
533 
534     dir_path[pos] = '/';
535 
536     return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
537 }
538 
539 oslFileError SAL_CALL osl_createDirectoryPath(
540     rtl_uString* aDirectoryUrl,
541     oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
542     void* pData)
543 {
544     if (aDirectoryUrl == NULL)
545         return osl_File_E_INVAL;
546 
547     rtl::OUString sys_path;
548     oslFileError osl_error = osl_getSystemPathFromFileURL_Ex(
549         aDirectoryUrl, &sys_path.pData, sal_False);
550 
551     if (osl_error != osl_File_E_None)
552         return osl_error;
553 
554     osl::systemPathRemoveSeparator(sys_path);
555 
556     // const_cast because sys_path is a local copy which we want to modify inplace instead of
557     // copy it into another buffer on the heap again
558     return create_dir_recursively_(sys_path.pData->buffer, aDirectoryCreationCallbackFunc, pData);
559 }
560 
561 /******************************************************************************
562  * C-String Function Declarations
563  *****************************************************************************/
564 
565 static oslFileError osl_psz_removeFile(const sal_Char* pszPath);
566 static oslFileError osl_psz_copyFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
567 static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
568 
569 
570 /******************************************************************************
571  * Static Module Utility Function Declarations
572  *****************************************************************************/
573 
574 static oslFileError  oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists);
575 static oslFileError  oslChangeFileModes(const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID);
576 static int           oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName);
577 static int           oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode);
578 static oslFileError  oslDoMoveFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
579 
580 /****************************************************************************/
581 /* osl_moveFile */
582 /****************************************************************************/
583 
584 oslFileError SAL_CALL osl_moveFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL )
585 {
586     char srcPath[PATH_MAX];
587     char destPath[PATH_MAX];
588     oslFileError eRet;
589 
590     OSL_ASSERT( ustrFileURL );
591     OSL_ASSERT( ustrDestURL );
592 
593     /* convert source url to system path */
594     eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
595     if( eRet != osl_File_E_None )
596         return eRet;
597 
598     /* convert destination url to system path */
599     eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
600     if( eRet != osl_File_E_None )
601         return eRet;
602 
603 #ifdef MACOSX
604     if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 )
605         return oslTranslateFileError( OSL_FET_ERROR, errno );
606 #endif/* MACOSX */
607 
608     return oslDoMoveFile( srcPath, destPath );
609 }
610 
611 /****************************************************************************/
612 /* osl_copyFile */
613 /****************************************************************************/
614 
615 oslFileError SAL_CALL osl_copyFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL )
616 {
617     char srcPath[PATH_MAX];
618     char destPath[PATH_MAX];
619     oslFileError eRet;
620 
621     OSL_ASSERT( ustrFileURL );
622     OSL_ASSERT( ustrDestURL );
623 
624     /* convert source url to system path */
625     eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
626     if( eRet != osl_File_E_None )
627         return eRet;
628 
629     /* convert destination url to system path */
630     eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
631     if( eRet != osl_File_E_None )
632         return eRet;
633 
634 #ifdef MACOSX
635     if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 )
636         return oslTranslateFileError( OSL_FET_ERROR, errno );
637 #endif/* MACOSX */
638 
639     return osl_psz_copyFile( srcPath, destPath );
640 }
641 
642 /****************************************************************************/
643 /* osl_removeFile */
644 /****************************************************************************/
645 
646 oslFileError SAL_CALL osl_removeFile( rtl_uString* ustrFileURL )
647 {
648     char path[PATH_MAX];
649     oslFileError eRet;
650 
651     OSL_ASSERT( ustrFileURL );
652 
653     /* convert file url to system path */
654     eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
655     if( eRet != osl_File_E_None )
656         return eRet;
657 
658 #ifdef MACOSX
659     if ( macxp_resolveAlias( path, PATH_MAX ) != 0 )
660         return oslTranslateFileError( OSL_FET_ERROR, errno );
661 #endif/* MACOSX */
662 
663     return osl_psz_removeFile( path );
664 }
665 
666 /******************************************************************************
667  * Utility Functions
668  *****************************************************************************/
669 
670 /*****************************************
671  * oslDoMoveFile
672  ****************************************/
673 
674 static oslFileError oslDoMoveFile( const sal_Char* pszPath, const sal_Char* pszDestPath)
675 {
676     oslFileError tErr=osl_File_E_invalidError;
677 
678     tErr = osl_psz_moveFile(pszPath,pszDestPath);
679     if ( tErr == osl_File_E_None )
680     {
681         return tErr;
682     }
683 
684     if ( tErr != osl_File_E_XDEV )
685     {
686         return tErr;
687     }
688 
689     tErr=osl_psz_copyFile(pszPath,pszDestPath);
690 
691     if ( tErr != osl_File_E_None )
692     {
693         oslFileError tErrRemove;
694         tErrRemove=osl_psz_removeFile(pszDestPath);
695         return tErr;
696     }
697 
698     tErr=osl_psz_removeFile(pszPath);
699 
700     return tErr;
701 }
702 
703 /*****************************************
704  * osl_psz_removeFile
705  ****************************************/
706 static oslFileError osl_psz_removeFile( const sal_Char* pszPath )
707 {
708     int nRet=0;
709     struct stat aStat;
710 
711     nRet = lstat(pszPath,&aStat);
712     if ( nRet < 0 )
713     {
714         nRet=errno;
715         return oslTranslateFileError(OSL_FET_ERROR, nRet);
716     }
717 
718     if ( S_ISDIR(aStat.st_mode) )
719     {
720         return osl_File_E_ISDIR;
721     }
722 
723     nRet = unlink(pszPath);
724     if ( nRet < 0 )
725     {
726         nRet=errno;
727         return oslTranslateFileError(OSL_FET_ERROR, nRet);
728     }
729 
730     return osl_File_E_None;
731 }
732 
733 /*****************************************
734  * osl_psz_moveFile
735  ****************************************/
736 
737 static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath)
738 {
739 
740     int nRet = 0;
741 
742     nRet = rename(pszPath,pszDestPath);
743 
744     if ( nRet < 0 )
745     {
746         nRet=errno;
747         return oslTranslateFileError(OSL_FET_ERROR, nRet);
748     }
749 
750     return osl_File_E_None;
751 }
752 
753 /*****************************************
754  * osl_psz_copyFile
755  ****************************************/
756 
757 static oslFileError osl_psz_copyFile( const sal_Char* pszPath, const sal_Char* pszDestPath )
758 {
759     time_t nAcTime=0;
760     time_t nModTime=0;
761     uid_t nUID=0;
762     gid_t nGID=0;
763     int nRet=0;
764     mode_t nMode=0;
765     struct stat aFileStat;
766     oslFileError tErr=osl_File_E_invalidError;
767     size_t nSourceSize=0;
768     int DestFileExists=1;
769 
770     /* mfe: does the source file really exists? */
771     nRet = lstat(pszPath,&aFileStat);
772 
773     if ( nRet < 0 )
774     {
775         nRet=errno;
776         return oslTranslateFileError(OSL_FET_ERROR, nRet);
777     }
778 
779     /* mfe: we do only copy files here! */
780     if ( S_ISDIR(aFileStat.st_mode) )
781     {
782         return osl_File_E_ISDIR;
783     }
784 
785     nSourceSize=(size_t)aFileStat.st_size;
786     nMode=aFileStat.st_mode;
787     nAcTime=aFileStat.st_atime;
788     nModTime=aFileStat.st_mtime;
789     nUID=aFileStat.st_uid;
790     nGID=aFileStat.st_gid;
791 
792     nRet = stat(pszDestPath,&aFileStat);
793     if ( nRet < 0 )
794     {
795         nRet=errno;
796 
797         if ( nRet == ENOENT )
798         {
799             DestFileExists=0;
800         }
801 /*      return oslTranslateFileError(nRet);*/
802     }
803 
804     /* mfe: the destination file must not be a directory! */
805     if ( nRet == 0 && S_ISDIR(aFileStat.st_mode) )
806     {
807         return osl_File_E_ISDIR;
808     }
809     else
810     {
811         /* mfe: file does not exists or is no dir */
812     }
813 
814     tErr = oslDoCopy(pszPath,pszDestPath,nMode,nSourceSize,DestFileExists);
815 
816     if ( tErr != osl_File_E_None )
817     {
818         return tErr;
819     }
820 
821     /*
822      *   mfe: ignore return code
823      *        since only the success of the copy is
824      *        important
825      */
826     oslChangeFileModes(pszDestPath,nMode,nAcTime,nModTime,nUID,nGID);
827 
828     return tErr;
829 }
830 
831 
832 /******************************************************************************
833  * Utility Functions
834  *****************************************************************************/
835 
836 /*****************************************
837  * oslDoCopy
838  ****************************************/
839 
840 #define TMP_DEST_FILE_EXTENSION ".osl-tmp"
841 
842 static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists)
843 {
844     int      nRet=0;
845     sal_Char pszTmpDestFile[PATH_MAX];
846     size_t   size_tmp_dest_buff = sizeof(pszTmpDestFile);
847 
848     /* Quick fix for #106048, the whole copy file function seems
849        to be erroneous anyway and needs to be rewritten.
850        Besides osl_copyFile is currently not used from AOO code.
851     */
852     memset(pszTmpDestFile, 0, size_tmp_dest_buff);
853 
854     if ( DestFileExists )
855     {
856         strncpy(pszTmpDestFile, pszDestFileName, size_tmp_dest_buff - 1);
857 
858         if ((strlen(pszTmpDestFile) + strlen(TMP_DEST_FILE_EXTENSION)) >= size_tmp_dest_buff)
859             return osl_File_E_NAMETOOLONG;
860 
861         strncat(pszTmpDestFile, TMP_DEST_FILE_EXTENSION, strlen(TMP_DEST_FILE_EXTENSION));
862 
863         /* FIXME: what if pszTmpDestFile already exists? */
864         /*        with getcanonical??? */
865         nRet=rename(pszDestFileName,pszTmpDestFile);
866     }
867 
868     /* mfe: should be S_ISREG */
869     if ( !S_ISLNK(nMode) )
870     {
871         /* copy SourceFile to DestFile */
872         nRet = oslDoCopyFile(pszSourceFileName,pszDestFileName,nSourceSize, nMode);
873     }
874     /* mfe: OK redundant at the moment */
875     else if ( S_ISLNK(nMode) )
876     {
877         nRet = oslDoCopyLink(pszSourceFileName,pszDestFileName);
878     }
879     else
880     {
881         /* mfe: what to do here? */
882         nRet=ENOSYS;
883     }
884 
885     if ( nRet > 0 && DestFileExists == 1 )
886     {
887         unlink(pszDestFileName);
888         rename(pszTmpDestFile,pszDestFileName);
889     }
890 
891     if ( nRet > 0 )
892     {
893         return oslTranslateFileError(OSL_FET_ERROR, nRet);
894     }
895 
896     if ( DestFileExists == 1 )
897     {
898         unlink(pszTmpDestFile);
899     }
900 
901     return osl_File_E_None;
902 }
903 
904 /*****************************************
905  * oslChangeFileModes
906  ****************************************/
907 
908 static oslFileError oslChangeFileModes( const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID)
909 {
910     int nRet=0;
911     struct utimbuf aTimeBuffer;
912 
913     nRet = chmod(pszFileName,nMode);
914     if ( nRet < 0 )
915     {
916         nRet=errno;
917         return oslTranslateFileError(OSL_FET_ERROR, nRet);
918     }
919 
920     aTimeBuffer.actime=nAcTime;
921     aTimeBuffer.modtime=nModTime;
922     nRet=utime(pszFileName,&aTimeBuffer);
923     if ( nRet < 0 )
924     {
925         nRet=errno;
926         return oslTranslateFileError(OSL_FET_ERROR, nRet);
927     }
928 
929     if ( nUID != getuid() )
930     {
931         nUID=getuid();
932     }
933 
934     nRet=chown(pszFileName,nUID,nGID);
935     if ( nRet < 0 )
936     {
937         nRet=errno;
938 
939         /* mfe: do not return an error here! */
940         /* return oslTranslateFileError(nRet);*/
941     }
942 
943     return osl_File_E_None;
944 }
945 
946 /*****************************************
947  * oslDoCopyLink
948  ****************************************/
949 
950 static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName)
951 {
952     int nRet=0;
953 
954     /* mfe: if dest file is symbolic link remove the link and place the file instead (hro says so) */
955     /* mfe: if source is a link copy the link and not the file it points to (hro says so) */
956     sal_Char pszLinkContent[PATH_MAX];
957 
958     pszLinkContent[0] = '\0';
959 
960     nRet = readlink(pszSourceFileName,pszLinkContent,PATH_MAX-1);
961 
962     if ( nRet < 0 )
963     {
964         nRet=errno;
965         return nRet;
966     }
967     else
968         pszLinkContent[ nRet ] = 0;
969 
970     nRet = symlink(pszLinkContent,pszDestFileName);
971 
972     if ( nRet < 0 )
973     {
974         nRet=errno;
975         return nRet;
976     }
977 
978     return 0;
979 }
980 
981 /*****************************************
982  * oslDoCopyFile
983  ****************************************/
984 
985 static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode)
986 {
987     int SourceFileFD=0;
988     int DestFileFD=0;
989     int nRet=0;
990 
991     SourceFileFD=open(pszSourceFileName,O_RDONLY);
992     if ( SourceFileFD < 0 )
993     {
994         nRet=errno;
995         return nRet;
996     }
997 
998     DestFileFD=open(pszDestFileName, O_WRONLY | O_CREAT, mode);
999 
1000     if ( DestFileFD < 0 )
1001     {
1002         nRet=errno;
1003         close(SourceFileFD);
1004         return nRet;
1005     }
1006 
1007     size_t nWritten = 0;
1008     size_t nRemains = nSourceSize;
1009 
1010     if ( nRemains )
1011     {
1012         /* mmap has problems, try the direct streaming */
1013         char pBuffer[0x8000];
1014         size_t nRead = 0;
1015 
1016         nRemains = nSourceSize;
1017 
1018         do
1019         {
1020             nRead = 0;
1021             nWritten = 0;
1022 
1023             size_t nToRead = std::min( (size_t)0x8000, nRemains );
1024             nRead = read( SourceFileFD, pBuffer, nToRead );
1025             if ( (size_t)-1 != nRead )
1026                 nWritten = write( DestFileFD, pBuffer, nRead );
1027 
1028             if ( (size_t)-1 != nWritten )
1029                 nRemains -= nWritten;
1030         }
1031         while( nRemains && (size_t)-1 != nRead && nRead == nWritten );
1032     }
1033 
1034     if ( nRemains )
1035     {
1036         if ( errno )
1037             nRet = errno;
1038         else
1039             nRet = ENOSPC;
1040     }
1041 
1042     close( SourceFileFD );
1043     if ( close( DestFileFD ) == -1 && nRet == 0 )
1044         nRet = errno;
1045 
1046     return nRet;
1047 }
1048