1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/file.hxx>
21 #include <osl/detail/file.h>
23 #include <osl/diagnose.h>
24 #include <osl/thread.h>
25 #include <osl/signal.h>
26 #include <rtl/alloc.h>
27 #include <rtl/string.hxx>
28 #include <sal/log.hxx>
31 #include "file_impl.hxx"
32 #include "file_error_transl.hxx"
33 #include "file_path_helper.hxx"
34 #include "file_url.hxx"
35 #include "uunxapi.hxx"
36 #include "readwrite_helper.hxx"
37 #include "unixerrnostring.hxx"
39 #include <sys/types.h>
56 #include <osl/detail/android-bootstrap.h>
59 /************************************************************************
62 * - Fix: check for corresponding struct sizes in exported functions
63 * - check size/use of oslDirectory
64 * - check size/use of oslDirectoryItem
65 ***********************************************************************/
71 OString strPath
; /* holds native directory path */
80 lo_apk_dir
* pApkDirStruct
;
86 DirectoryItem_Impl::DirectoryItem_Impl(
87 OString strFilePath
, unsigned char DType
)
88 : m_strFilePath (std::move(strFilePath
)),
93 DirectoryItem_Impl::~DirectoryItem_Impl()
97 void DirectoryItem_Impl::acquire()
101 void DirectoryItem_Impl::release()
103 if (--m_RefCount
== 0)
107 oslFileType
DirectoryItem_Impl::getFileType() const
111 #ifdef _DIRENT_HAVE_D_TYPE
113 return osl_File_Type_Link
;
115 return osl_File_Type_Directory
;
117 return osl_File_Type_Regular
;
119 return osl_File_Type_Fifo
;
121 return osl_File_Type_Socket
;
124 return osl_File_Type_Special
;
125 #endif /* _DIRENT_HAVE_D_TYPE */
129 return osl_File_Type_Unknown
;
132 static oslFileError
osl_psz_createDirectory(
133 char const * pszPath
, sal_uInt32 flags
);
134 static oslFileError
osl_psz_removeDirectory(const char* pszPath
);
136 oslFileError SAL_CALL
osl_openDirectory(rtl_uString
* ustrDirectoryURL
, oslDirectory
* pDirectory
)
142 if ((ustrDirectoryURL
== nullptr) || (ustrDirectoryURL
->length
== 0) || (pDirectory
== nullptr))
143 return osl_File_E_INVAL
;
145 /* convert file URL to system path */
146 eRet
= osl::detail::convertUrlToPathname(OUString::unacquired(&ustrDirectoryURL
), &path
);
148 if( eRet
!= osl_File_E_None
)
151 osl_systemPathRemoveSeparator(path
.pData
);
155 auto const n
= std::max(int(path
.getLength() + 1), int(PATH_MAX
));
156 auto const tmp
= std::make_unique
<char[]>(n
);
157 std::strcpy(tmp
.get(), path
.getStr());
158 if (macxp_resolveAlias(tmp
.get(), n
) != 0) {
159 return oslTranslateFileError(errno
);
161 path
= OString(tmp
.get(), std::strlen(tmp
.get()));
166 if( strncmp( path
.getStr(), "/assets/", sizeof( "/assets/" ) - 1) == 0 )
168 lo_apk_dir
*pdir
= lo_apk_opendir( path
.getStr() );
172 DirectoryImpl
* pDirImpl
= new(std::nothrow
) DirectoryImpl
;
176 pDirImpl
->eKind
= DirectoryImpl::KIND_ASSETS
;
177 pDirImpl
->pApkDirStruct
= pdir
;
178 pDirImpl
->strPath
= path
;
180 *pDirectory
= (oslDirectory
) pDirImpl
;
181 return osl_File_E_None
;
186 lo_apk_closedir( pdir
);
194 DIR *pdir
= opendir( path
.getStr() );
198 SAL_INFO("sal.file", "opendir(" << path
<< ") => " << pdir
);
200 /* create and initialize impl structure */
201 DirectoryImpl
* pDirImpl
= new(std::nothrow
) DirectoryImpl
;
205 pDirImpl
->pDirStruct
= pdir
;
206 pDirImpl
->strPath
= path
;
208 pDirImpl
->eKind
= DirectoryImpl::KIND_DIRENT
;
210 *pDirectory
= static_cast<oslDirectory
>(pDirImpl
);
211 return osl_File_E_None
;
219 SAL_INFO("sal.file", "opendir(" << path
<< "): " << UnixErrnoString(e
));
220 // Restore errno after possible modification by SAL_INFO above
225 return oslTranslateFileError(errno
);
228 oslFileError SAL_CALL
osl_closeDirectory(oslDirectory pDirectory
)
230 SAL_WARN_IF(!pDirectory
, "sal.file", "pDirectory is nullptr");
231 DirectoryImpl
* pDirImpl
= static_cast<DirectoryImpl
*>(pDirectory
);
232 oslFileError err
= osl_File_E_None
;
235 return osl_File_E_INVAL
;
238 if (pDirImpl
->eKind
== DirectoryImpl::KIND_ASSETS
)
240 if (lo_apk_closedir(pDirImpl
->pApkDirStruct
))
246 if (closedir( pDirImpl
->pDirStruct
) != 0)
249 SAL_INFO("sal.file", "closedir(" << pDirImpl
->pDirStruct
<< "): " << UnixErrnoString(e
));
250 err
= oslTranslateFileError(e
);
253 SAL_INFO("sal.file", "closedir(" << pDirImpl
->pDirStruct
<< "): OK");
261 /**********************************************
264 * readdir wrapper, filters out "." and ".."
266 *********************************************/
268 static struct dirent
* osl_readdir_impl_(DIR* pdir
)
270 struct dirent
* pdirent
;
272 while ((pdirent
= readdir(pdir
)) != nullptr)
274 if ((strcmp(pdirent
->d_name
, ".") == 0) || (strcmp(pdirent
->d_name
, "..") == 0))
282 oslFileError SAL_CALL
osl_getNextDirectoryItem(oslDirectory pDirectory
,
283 oslDirectoryItem
* pItem
, SAL_UNUSED_PARAMETER sal_uInt32
/*uHint*/)
285 SAL_WARN_IF(!pDirectory
, "sal.file", "pDirectory is nullptr");
286 SAL_WARN_IF(!pItem
, "sal.file", "pItem is nullptr");
288 DirectoryImpl
* pDirImpl
= static_cast<DirectoryImpl
*>(pDirectory
);
290 struct dirent
* pEntry
;
292 if ((pDirectory
== nullptr) || (pItem
== nullptr))
293 return osl_File_E_INVAL
;
296 if(pDirImpl
->eKind
== DirectoryImpl::KIND_ASSETS
)
298 pEntry
= lo_apk_readdir(pDirImpl
->pApkDirStruct
);
303 pEntry
= osl_readdir_impl_(pDirImpl
->pDirStruct
);
307 return osl_File_E_NOENT
;
309 char const * filename
= pEntry
->d_name
;
312 // convert decomposed filename to precomposed UTF-8
313 char composed_name
[BUFSIZ
];
314 CFMutableStringRef strRef
= CFStringCreateMutable(nullptr, 0 );
315 CFStringAppendCString(strRef
, filename
, kCFStringEncodingUTF8
); // UTF8 is default on Mac OSX
316 CFStringNormalize(strRef
, kCFStringNormalizationFormC
);
317 CFStringGetCString(strRef
, composed_name
, BUFSIZ
, kCFStringEncodingUTF8
);
319 filename
= composed_name
;
322 strFileName
= OString(filename
, strlen(filename
));
324 auto const strFilePath
= osl::systemPathMakeAbsolutePath(pDirImpl
->strPath
, strFileName
);
326 DirectoryItem_Impl
* pImpl
= static_cast< DirectoryItem_Impl
* >(*pItem
);
332 #ifdef _DIRENT_HAVE_D_TYPE
333 pImpl
= new DirectoryItem_Impl(strFilePath
, pEntry
->d_type
);
335 pImpl
= new DirectoryItem_Impl(strFilePath
);
336 #endif /* _DIRENT_HAVE_D_TYPE */
339 return osl_File_E_None
;
342 oslFileError SAL_CALL
osl_getDirectoryItem(rtl_uString
* ustrFileURL
, oslDirectoryItem
* pItem
)
344 OString strSystemPath
;
345 oslFileError osl_error
= osl_File_E_INVAL
;
347 if ((!ustrFileURL
) || (ustrFileURL
->length
== 0) || (!pItem
))
348 return osl_File_E_INVAL
;
350 osl_error
= osl::detail::convertUrlToPathname(OUString::unacquired(&ustrFileURL
), &strSystemPath
);
351 if (osl_error
!= osl_File_E_None
)
354 osl_systemPathRemoveSeparator(strSystemPath
.pData
);
356 if (osl::access(strSystemPath
, F_OK
) == -1)
358 osl_error
= oslTranslateFileError(errno
);
362 *pItem
= new DirectoryItem_Impl(std::move(strSystemPath
));
368 oslFileError SAL_CALL
osl_acquireDirectoryItem( oslDirectoryItem Item
)
370 DirectoryItem_Impl
* pImpl
= static_cast< DirectoryItem_Impl
* >(Item
);
371 if (pImpl
== nullptr)
372 return osl_File_E_INVAL
;
375 return osl_File_E_None
;
378 oslFileError SAL_CALL
osl_releaseDirectoryItem( oslDirectoryItem Item
)
380 DirectoryItem_Impl
* pImpl
= static_cast< DirectoryItem_Impl
* >(Item
);
381 if (pImpl
== nullptr)
382 return osl_File_E_INVAL
;
385 return osl_File_E_None
;
388 oslFileError SAL_CALL
osl_createDirectory( rtl_uString
* ustrDirectoryURL
)
390 return osl_createDirectoryWithFlags(
391 ustrDirectoryURL
, osl_File_OpenFlag_Read
| osl_File_OpenFlag_Write
);
394 oslFileError
osl_createDirectoryWithFlags(
395 rtl_uString
* ustrDirectoryURL
, sal_uInt32 flags
)
400 SAL_WARN_IF((!ustrDirectoryURL
) || (ustrDirectoryURL
->length
== 0),
401 "sal.file", "Invalid directory URL");
403 /* convert directory url to system path */
404 eRet
= FileURLToPath( path
, PATH_MAX
, ustrDirectoryURL
);
405 if( eRet
!= osl_File_E_None
)
409 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
410 return oslTranslateFileError( errno
);
413 return osl_psz_createDirectory( path
, flags
);
416 oslFileError SAL_CALL
osl_removeDirectory( rtl_uString
* ustrDirectoryURL
)
421 SAL_WARN_IF((!ustrDirectoryURL
) || (ustrDirectoryURL
->length
== 0),
422 "sal.file", "Invalid directory URL");
424 /* convert directory url to system path */
425 eRet
= FileURLToPath( path
, PATH_MAX
, ustrDirectoryURL
);
426 if( eRet
!= osl_File_E_None
)
430 if ( macxp_resolveAlias( path
, PATH_MAX
) != 0 )
431 return oslTranslateFileError( errno
);
434 return osl_psz_removeDirectory( path
);
437 oslFileError
osl_psz_createDirectory(char const * pszPath
, sal_uInt32 flags
)
441 = (((flags
& osl_File_OpenFlag_Read
) == 0
443 : ((flags
& osl_File_OpenFlag_Private
) == 0
444 ? S_IRUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
445 : S_IRUSR
| S_IXUSR
))
446 | ((flags
& osl_File_OpenFlag_Write
) == 0
448 : ((flags
& osl_File_OpenFlag_Private
) == 0
449 ? S_IWUSR
| S_IWGRP
| S_IWOTH
452 nRet
= mkdir(pszPath
,mode
);
457 SAL_INFO("sal.file", "mkdir(" << pszPath
<< ",0" << std::oct
<< mode
<< std::dec
<< "): " << UnixErrnoString(nRet
));
458 return oslTranslateFileError(nRet
);
461 SAL_INFO("sal.file", "mkdir(" << pszPath
<< ",0" << std::oct
<< mode
<< std::dec
<< "): OK");
463 return osl_File_E_None
;
466 static oslFileError
osl_psz_removeDirectory( const char* pszPath
)
468 int nRet
= rmdir(pszPath
);
473 SAL_INFO("sal.file", "rmdir(" << pszPath
<< "): " << UnixErrnoString(nRet
));
474 return oslTranslateFileError(nRet
);
477 SAL_INFO("sal.file", "rmdir(" << pszPath
<< "): OK");
479 return osl_File_E_None
;
482 static int path_make_parent(char* path
)
484 int i
= rtl_str_lastIndexOfChar(path
, '/');
494 static int create_dir_with_callback(
495 char* directory_path
,
496 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
499 if (osl::mkdir(directory_path
, S_IRWXU
| S_IRWXG
| S_IRWXO
) == 0)
501 if (aDirectoryCreationCallbackFunc
)
504 osl::detail::convertPathnameToUrl(directory_path
, &url
);
505 aDirectoryCreationCallbackFunc(pData
, url
.pData
);
512 static oslFileError
create_dir_recursively_(
514 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
517 OSL_PRECOND((rtl_str_getLength(dir_path
) > 0) && ((dir_path
+ (rtl_str_getLength(dir_path
) - 1)) != (dir_path
+ rtl_str_lastIndexOfChar(dir_path
, '/'))),
518 "Path must not end with a slash");
520 int native_err
= create_dir_with_callback(
521 dir_path
, aDirectoryCreationCallbackFunc
, pData
);
524 return osl_File_E_None
;
526 if (native_err
!= ENOENT
)
527 return oslTranslateFileError(native_err
);
529 // we step back until '/a_dir' at maximum because
530 // we should get an error unequal ENOENT when
531 // we try to create 'a_dir' at '/' and would so
533 int pos
= path_make_parent(dir_path
);
535 oslFileError osl_error
= create_dir_recursively_(
536 dir_path
, aDirectoryCreationCallbackFunc
, pData
);
538 if (osl_error
!= osl_File_E_None
&& osl_error
!= osl_File_E_EXIST
)
543 return create_dir_recursively_(dir_path
, aDirectoryCreationCallbackFunc
, pData
);
546 oslFileError SAL_CALL
osl_createDirectoryPath(
547 rtl_uString
* aDirectoryUrl
,
548 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
551 if (aDirectoryUrl
== nullptr)
552 return osl_File_E_INVAL
;
555 oslFileError osl_error
= osl::detail::convertUrlToPathname(
556 OUString::unacquired(&aDirectoryUrl
), &sys_path
);
558 if (osl_error
!= osl_File_E_None
)
561 osl::systemPathRemoveSeparator(sys_path
);
563 // const_cast because sys_path is a local copy which we want to modify inplace instead of
564 // copy it into another buffer on the heap again
565 return create_dir_recursively_(sys_path
.pData
->buffer
, aDirectoryCreationCallbackFunc
, pData
);
568 static oslFileError
osl_unlinkFile(const char* pszPath
);
569 static oslFileError
osl_psz_copyFile(const char* pszPath
, const char* pszDestPath
, bool preserveMetadata
);
570 static oslFileError
osl_psz_moveFile(const char* pszPath
, const char* pszDestPath
);
572 static oslFileError
oslDoCopy(const char* pszSourceFileName
, const char* pszDestFileName
, mode_t nMode
, size_t nSourceSize
, bool DestFileExists
);
573 static void attemptChangeMetadata(const char* pszFileName
, mode_t nMode
, time_t nAcTime
, time_t nModTime
, uid_t nUID
, gid_t nGID
);
574 static int oslDoCopyLink(const char* pszSourceFileName
, const char* pszDestFileName
);
575 static int oslDoCopyFile(const char* pszSourceFileName
, const char* pszDestFileName
, size_t nSourceSize
, mode_t mode
);
576 static oslFileError
oslDoMoveFile(const char* pszPath
, const char* pszDestPath
);
578 oslFileError SAL_CALL
osl_moveFile( rtl_uString
* ustrFileURL
, rtl_uString
* ustrDestURL
)
580 char srcPath
[PATH_MAX
];
581 char destPath
[PATH_MAX
];
584 SAL_WARN_IF((!ustrFileURL
) || (ustrFileURL
->length
== 0), "sal.file", "Invalid source file URL");
585 SAL_WARN_IF((!ustrDestURL
) || (ustrDestURL
->length
== 0), "sal.file", "Invalid destination file URL");
587 /* convert source url to system path */
588 eRet
= FileURLToPath( srcPath
, PATH_MAX
, ustrFileURL
);
589 if( eRet
!= osl_File_E_None
)
592 /* convert destination url to system path */
593 eRet
= FileURLToPath( destPath
, PATH_MAX
, ustrDestURL
);
594 if( eRet
!= osl_File_E_None
)
598 if ( macxp_resolveAlias( srcPath
, PATH_MAX
) != 0 || macxp_resolveAlias( destPath
, PATH_MAX
) != 0 )
599 return oslTranslateFileError( errno
);
602 return oslDoMoveFile( srcPath
, destPath
);
605 oslFileError SAL_CALL
osl_replaceFile(rtl_uString
* ustrFileURL
, rtl_uString
* ustrDestURL
)
608 char destPath
[PATH_MAX
];
609 oslFileError eRet
= FileURLToPath(destPath
, PATH_MAX
, ustrDestURL
);
610 if (eRet
== osl_File_E_None
)
612 struct stat aFileStat
;
613 // coverity[fs_check_call] - unavoidable TOCTOU
614 int nRet
= stat(destPath
, &aFileStat
);
618 SAL_INFO("sal.file", "stat(" << destPath
<< "): " << UnixErrnoString(nRet
));
622 nGid
= aFileStat
.st_gid
;
626 eRet
= osl_moveFile(ustrFileURL
, ustrDestURL
);
628 if (eRet
== osl_File_E_None
&& nGid
!= -1)
630 int nRet
= chown(destPath
, -1, nGid
);
635 "chown(" << destPath
<< "-1, " << nGid
<< "): " << UnixErrnoString(nRet
));
642 oslFileError SAL_CALL
osl_copyFile( rtl_uString
* ustrFileURL
, rtl_uString
* ustrDestURL
)
644 char srcPath
[PATH_MAX
];
645 char destPath
[PATH_MAX
];
648 SAL_WARN_IF((!ustrFileURL
) || (ustrFileURL
->length
== 0), "sal.file", "Invalid source file URL");
649 SAL_WARN_IF((!ustrDestURL
) || (ustrDestURL
->length
== 0), "sal.file", "Invalid destination file URL");
651 /* convert source url to system path */
652 eRet
= FileURLToPath( srcPath
, PATH_MAX
, ustrFileURL
);
653 if( eRet
!= osl_File_E_None
)
656 /* convert destination url to system path */
657 eRet
= FileURLToPath( destPath
, PATH_MAX
, ustrDestURL
);
658 if( eRet
!= osl_File_E_None
)
662 if ( macxp_resolveAlias( srcPath
, PATH_MAX
) != 0 || macxp_resolveAlias( destPath
, PATH_MAX
) != 0 )
663 return oslTranslateFileError( errno
);
666 return osl_psz_copyFile( srcPath
, destPath
, false );
669 oslFileError SAL_CALL
osl_removeFile(rtl_uString
* ustrFileURL
)
674 SAL_WARN_IF(!ustrFileURL
|| ustrFileURL
->length
== 0, "sal.file", "Invalid file URL");
676 /* convert file url to system path */
677 eRet
= FileURLToPath(path
, PATH_MAX
, ustrFileURL
);
678 if (eRet
!= osl_File_E_None
)
682 if (macxp_resolveAlias(path
, PATH_MAX
) != 0)
683 return oslTranslateFileError(errno
);
686 return osl_unlinkFile(path
);
689 static oslFileError
oslDoMoveFile(const char* pszPath
, const char* pszDestPath
)
691 oslFileError tErr
= osl_psz_moveFile(pszPath
,pszDestPath
);
692 if (tErr
== osl_File_E_None
)
695 if (tErr
!= osl_File_E_XDEV
)
698 tErr
= osl_psz_copyFile(pszPath
,pszDestPath
, true);
700 if (tErr
!= osl_File_E_None
)
702 osl_unlinkFile(pszDestPath
);
706 tErr
= osl_unlinkFile(pszPath
);
711 static oslFileError
osl_unlinkFile(const char* pszPath
)
716 nRet
= lstat_c(pszPath
,&aStat
);
720 return oslTranslateFileError(nRet
);
723 if (S_ISDIR(aStat
.st_mode
))
724 return osl_File_E_ISDIR
;
726 nRet
= unlink(pszPath
);
730 SAL_INFO("sal.file", "unlink(" << pszPath
<< "): " << UnixErrnoString(nRet
));
731 return oslTranslateFileError(nRet
);
734 SAL_INFO("sal.file", "unlink(" << pszPath
<< "): OK");
736 return osl_File_E_None
;
739 static oslFileError
osl_psz_moveFile(const char* pszPath
, const char* pszDestPath
)
741 int nRet
= rename(pszPath
,pszDestPath
);
746 SAL_INFO("sal.file", "rename(" << pszPath
<< "," << pszDestPath
<< "): " << UnixErrnoString(nRet
));
747 return oslTranslateFileError(nRet
);
750 SAL_INFO("sal.file", "rename(" << pszPath
<< "," << pszDestPath
<< "): OK");
752 return osl_File_E_None
;
755 static oslFileError
osl_psz_copyFile( const char* pszPath
, const char* pszDestPath
, bool preserveMetadata
)
763 struct stat aFileStat
;
764 oslFileError tErr
=osl_File_E_invalidError
;
765 size_t nSourceSize
=0;
766 bool DestFileExists
=true;
768 /* mfe: does the source file really exists? */
769 nRet
= lstat_c(pszPath
,&aFileStat
);
774 return oslTranslateFileError(nRet
);
777 /* we do only copy files here */
778 if (S_ISDIR(aFileStat
.st_mode
))
779 return osl_File_E_ISDIR
;
781 nSourceSize
= static_cast< size_t >(aFileStat
.st_size
);
782 nMode
= aFileStat
.st_mode
;
783 nAcTime
= aFileStat
.st_atime
;
784 nModTime
= aFileStat
.st_mtime
;
785 nUID
= aFileStat
.st_uid
;
786 nGID
= aFileStat
.st_gid
;
788 nRet
= stat_c(pszDestPath
,&aFileStat
);
794 // Checking for nonexistent files at least in the iCloud cache directory (like
795 // "/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/helloodt0.odt" fails
796 // with EPERM, not ENOENT.
798 DestFileExists
=false;
802 DestFileExists
=false;
805 /* mfe: the destination file must not be a directory! */
806 if (nRet
== 0 && S_ISDIR(aFileStat
.st_mode
))
807 return osl_File_E_ISDIR
;
809 /* mfe: file does not exists or is no dir */
811 tErr
= oslDoCopy(pszPath
, pszDestPath
, nMode
, nSourceSize
, DestFileExists
);
813 if (tErr
!= osl_File_E_None
)
816 if (preserveMetadata
)
817 attemptChangeMetadata(pszDestPath
, nMode
, nAcTime
, nModTime
, nUID
, nGID
);
822 static oslFileError
oslDoCopy(const char* pszSourceFileName
, const char* pszDestFileName
, mode_t nMode
, size_t nSourceSize
, bool DestFileExists
)
827 if ( DestFileExists
)
829 //TODO: better pick a temp file name instead of adding .osl-tmp:
830 // use the destination file to avoid EXDEV /* Cross-device link */
831 tmpDestFile
= pszDestFileName
+ OString::Concat(".osl-tmp");
832 if (rename(pszDestFileName
, tmpDestFile
.getStr()) != 0)
835 SAL_INFO("sal.file", "rename(" << pszDestFileName
<< ", " << tmpDestFile
836 << "): " << UnixErrnoString(e
));
839 DestFileExists
= false;
843 return osl_File_E_EXIST
; // for want of a better error code
848 SAL_INFO("sal.file", "rename(" << pszDestFileName
<< ", " << tmpDestFile
853 if ( S_ISREG(nMode
) )
855 /* copy SourceFile to DestFile */
856 nRet
= oslDoCopyFile(pszSourceFileName
,pszDestFileName
,nSourceSize
, nMode
);
858 else if ( S_ISLNK(nMode
) )
860 nRet
= oslDoCopyLink(pszSourceFileName
,pszDestFileName
);
867 if ( nRet
> 0 && DestFileExists
)
869 if (unlink(pszDestFileName
) != 0)
872 SAL_INFO("sal.file", "unlink(" << pszDestFileName
<< "): " << UnixErrnoString(e
));
875 SAL_INFO("sal.file", "unlink(" << pszDestFileName
<< "): OK");
877 if (rename(tmpDestFile
.getStr(), pszDestFileName
) != 0)
880 SAL_INFO("sal.file", "rename(" << tmpDestFile
<< ", " << pszDestFileName
881 << "): " << UnixErrnoString(e
));
884 SAL_INFO("sal.file", "rename(" << tmpDestFile
<< ", " << pszDestFileName
<< "): OK");
889 return oslTranslateFileError(nRet
);
892 if ( DestFileExists
)
894 unlink(tmpDestFile
.getStr());
897 return osl_File_E_None
;
900 void attemptChangeMetadata( const char* pszFileName
, mode_t nMode
, time_t nAcTime
, time_t nModTime
, uid_t nUID
, gid_t nGID
)
902 struct utimbuf aTimeBuffer
;
904 #if !defined AT_FDCWD
905 if (!S_ISLNK(nMode
) && chmod(pszFileName
, nMode
) < 0)
907 if ( fchmodat(AT_FDCWD
, pszFileName
, nMode
, AT_SYMLINK_NOFOLLOW
) < 0 )
911 SAL_INFO("sal.file", "chmod(" << pszFileName
<< ",0" << std::oct
<< nMode
<< std::dec
<<"): " << UnixErrnoString(e
));
914 SAL_INFO("sal.file", "chmod(" << pszFileName
<< ",0" << std::oct
<< nMode
<< std::dec
<<"): OK");
916 // No way to change utime of a symlink itself:
919 aTimeBuffer
.actime
=nAcTime
;
920 aTimeBuffer
.modtime
=nModTime
;
921 if ( utime(pszFileName
,&aTimeBuffer
) < 0 )
924 SAL_INFO("sal.file", "utime(" << pszFileName
<< "): errno " << e
);
928 if ( nUID
!= getuid() )
932 if ( lchown(pszFileName
,nUID
,nGID
) < 0 )
935 SAL_INFO("sal.file", "lchown(" << pszFileName
<< "): errno " << e
);
938 SAL_INFO("sal.file", "lchown(" << pszFileName
<< "): OK");
941 static int oslDoCopyLink(const char* pszSourceFileName
, const char* pszDestFileName
)
945 /* mfe: if dest file is symbolic link remove the link and place the file instead (hro says so) */
946 /* mfe: if source is a link copy the link and not the file it points to (hro says so) */
947 char pszLinkContent
[PATH_MAX
+1];
949 pszLinkContent
[0] = '\0';
951 nRet
= readlink(pszSourceFileName
,pszLinkContent
,PATH_MAX
);
959 pszLinkContent
[ nRet
] = 0;
961 nRet
= symlink(pszLinkContent
,pszDestFileName
);
972 static int oslDoCopyFile(const char* pszSourceFileName
, const char* pszDestFileName
, size_t nSourceSize
, mode_t mode
)
974 oslFileHandle SourceFileFH
=nullptr;
978 if (openFilePath(pszSourceFileName
,
980 osl_File_OpenFlag_Read
|osl_File_OpenFlag_NoLock
|osl_File_OpenFlag_NoExcl
, mode_t(-1)) != osl_File_E_None
)
982 // Let's hope errno is still set relevantly after openFilePath...
987 DestFileFD
=open(pszDestFileName
, O_WRONLY
| O_CREAT
, mode
);
989 if ( DestFileFD
< 0 )
992 SAL_INFO("sal.file", "open(" << pszDestFileName
<< ",O_WRONLY|O_CREAT,0" << std::oct
<< mode
<< std::dec
<< "): " << UnixErrnoString(nRet
));
993 osl_closeFile(SourceFileFH
);
997 SAL_INFO("sal.file", "open(" << pszDestFileName
<< ",O_WRONLY|O_CREAT,0" << std::oct
<< mode
<< std::dec
<< "): OK");
999 size_t nRemains
= nSourceSize
;
1003 /* mmap has problems, try the direct streaming */
1004 char pBuffer
[0x7FFF];
1008 size_t nToRead
= std::min( sizeof(pBuffer
), nRemains
);
1011 if ( osl_readFile( SourceFileFH
, pBuffer
, nToRead
, &nRead
) != osl_File_E_None
|| nRead
> nToRead
|| nRead
== 0 )
1014 succeeded
= safeWrite( DestFileFD
, pBuffer
, nRead
);
1018 // We know nRead <= nToRead, so it must fit in a size_t
1019 nRemains
-= static_cast<size_t>(nRead
);
1032 osl_closeFile( SourceFileFH
);
1033 if ( close( DestFileFD
) == -1 )
1036 SAL_INFO("sal.file", "close(" << DestFileFD
<< "): " << UnixErrnoString(e
));
1041 SAL_INFO("sal.file", "close(" << DestFileFD
<< "): OK");
1046 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */