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