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