diff options
Diffstat (limited to 'sal/osl/unx/file_misc.cxx')
-rw-r--r-- | sal/osl/unx/file_misc.cxx | 1101 |
1 files changed, 1101 insertions, 0 deletions
diff --git a/sal/osl/unx/file_misc.cxx b/sal/osl/unx/file_misc.cxx new file mode 100644 index 000000000..95141420e --- /dev/null +++ b/sal/osl/unx/file_misc.cxx @@ -0,0 +1,1101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "osl/file.hxx" + +#include "osl/diagnose.h" +#include "osl/thread.h" +#include <osl/signal.h> +#include "rtl/alloc.h" + +#include "system.h" +#include "file_impl.hxx" +#include "file_error_transl.h" +#include "file_path_helper.hxx" +#include "file_url.h" +#include "uunxapi.hxx" + +#include <sys/types.h> +#include <errno.h> +#include <dirent.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include <algorithm> + +/************************************************************************ + * ToDo + * + * - Fix: check for corresponding struct sizes in exported functions + * - check size/use of oslDirectory + * - check size/use of oslDirectoryItem + ***********************************************************************/ +/****************************************************************************** + * + * Data Type Definition + * + ******************************************************************************/ + +typedef struct +{ + rtl_uString* ustrPath; /* holds native directory path */ + DIR* pDirStruct; +} oslDirectoryImpl; + +#if 0 +/* FIXME: reintroducing this may save some extra bytes per Item */ +typedef struct +{ + rtl_uString* ustrFileName; /* holds native file name */ + rtl_uString* ustrDirPath; /* holds native dir path */ + sal_uInt32 RefCount; +} oslDirectoryItemImpl; +#endif + +DirectoryItem_Impl::DirectoryItem_Impl( + rtl_uString * ustrFilePath, unsigned char DType) + : m_RefCount (1), + m_ustrFilePath (ustrFilePath), + m_DType (DType) +{ + if (m_ustrFilePath != 0) + rtl_uString_acquire(m_ustrFilePath); +} +DirectoryItem_Impl::~DirectoryItem_Impl() +{ + if (m_ustrFilePath != 0) + rtl_uString_release(m_ustrFilePath); +} + +void * DirectoryItem_Impl::operator new(size_t n) +{ + return rtl_allocateMemory(n); +} +void DirectoryItem_Impl::operator delete(void * p, size_t) +{ + rtl_freeMemory(p); +} + +void DirectoryItem_Impl::acquire() +{ + ++m_RefCount; +} +void DirectoryItem_Impl::release() +{ + if (0 == --m_RefCount) + delete this; +} + +oslFileType DirectoryItem_Impl::getFileType() const +{ + switch (m_DType) + { +#ifdef _DIRENT_HAVE_D_TYPE + case DT_LNK: + return osl_File_Type_Link; + case DT_DIR: + return osl_File_Type_Directory; + case DT_REG: + return osl_File_Type_Regular; + case DT_FIFO: + return osl_File_Type_Fifo; + case DT_SOCK: + return osl_File_Type_Socket; + case DT_CHR: + case DT_BLK: + return osl_File_Type_Special; +#endif /* _DIRENT_HAVE_D_TYPE */ + default: + break; + } + return osl_File_Type_Unknown; +} + +/****************************************************************************** + * + * C-String Function Declarations + * + *****************************************************************************/ + +static oslFileError osl_psz_createDirectory(const sal_Char* pszPath); +static oslFileError osl_psz_removeDirectory(const sal_Char* pszPath); + +/******************************************************************* + * osl_openDirectory + ******************************************************************/ + +oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirectory* pDirectory) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError eRet; + + char path[PATH_MAX]; + + if ((0 == ustrDirectoryURL) || (0 == ustrDirectoryURL->length) || (0 == pDirectory)) + return osl_File_E_INVAL; + + /* convert file URL to system path */ + eRet = osl_getSystemPathFromFileURL_Ex(ustrDirectoryURL, &ustrSystemPath, sal_False); + + if( osl_File_E_None != eRet ) + return eRet; + + osl_systemPathRemoveSeparator(ustrSystemPath); + + /* convert unicode path to text */ + if ( UnicodeToText( path, PATH_MAX, ustrSystemPath->buffer, ustrSystemPath->length ) +#ifdef MACOSX + && macxp_resolveAlias( path, PATH_MAX ) == 0 +#endif /* MACOSX */ + ) + { + /* open directory */ + DIR *pdir = opendir( path ); + + if( pdir ) + { + /* create and initialize impl structure */ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) ); + + if( pDirImpl ) + { + pDirImpl->pDirStruct = pdir; + pDirImpl->ustrPath = ustrSystemPath; + + *pDirectory = (oslDirectory) pDirImpl; + return osl_File_E_None; + } + else + { + errno = ENOMEM; + closedir( pdir ); + } + } + else + { +#ifdef DEBUG_OSL_FILE + perror ("osl_openDirectory"); fprintf (stderr, path); +#endif + } + } + + rtl_uString_release( ustrSystemPath ); + + return oslTranslateFileError(OSL_FET_ERROR, errno); +} + +/****************************************************************************/ +/* osl_closeDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory ) +{ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) Directory; + oslFileError err = osl_File_E_None; + + OSL_ASSERT( Directory ); + + if( NULL == pDirImpl ) + return osl_File_E_INVAL; + + /* close directory */ + if( closedir( pDirImpl->pDirStruct ) ) + { + err = oslTranslateFileError(OSL_FET_ERROR, errno); + } + + /* cleanup members */ + rtl_uString_release( pDirImpl->ustrPath ); + + rtl_freeMemory( pDirImpl ); + + return err; +} + +/********************************************** + * osl_readdir_impl_ + * + * readdir wrapper, filters out "." and ".." + * on request + *********************************************/ + +static struct dirent* osl_readdir_impl_(DIR* pdir, sal_Bool bFilterLocalAndParentDir) +{ + struct dirent* pdirent; + + while ((pdirent = readdir(pdir)) != NULL) + { + if (bFilterLocalAndParentDir && + ((0 == strcmp(pdirent->d_name, ".")) || (0 == strcmp(pdirent->d_name, "..")))) + continue; + else + break; + } + + return pdirent; +} + +/**************************************************************************** + * osl_getNextDirectoryItem + ***************************************************************************/ + +oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirectoryItem* pItem, sal_uInt32 /*uHint*/) +{ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*)Directory; + rtl_uString* ustrFileName = NULL; + rtl_uString* ustrFilePath = NULL; + struct dirent* pEntry; + + OSL_ASSERT(Directory); + OSL_ASSERT(pItem); + + if ((NULL == Directory) || (NULL == pItem)) + return osl_File_E_INVAL; + + pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, sal_True); + + if (NULL == pEntry) + return osl_File_E_NOENT; + + +#if defined(MACOSX) + + // convert decomposed filename to precomposed unicode + char composed_name[BUFSIZ]; + CFMutableStringRef strRef = CFStringCreateMutable (NULL, 0 ); + CFStringAppendCString( strRef, pEntry->d_name, kCFStringEncodingUTF8 ); //UTF8 is default on Mac OSX + CFStringNormalize( strRef, kCFStringNormalizationFormC ); + CFStringGetCString( strRef, composed_name, BUFSIZ, kCFStringEncodingUTF8 ); + CFRelease( strRef ); + rtl_string2UString( &ustrFileName, composed_name, strlen( composed_name), + osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + +#else // not MACOSX + /* convert file name to unicode */ + rtl_string2UString( &ustrFileName, pEntry->d_name, strlen( pEntry->d_name ), + osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); + OSL_ASSERT(ustrFileName != 0); + +#endif + + osl_systemPathMakeAbsolutePath(pDirImpl->ustrPath, ustrFileName, &ustrFilePath); + rtl_uString_release( ustrFileName ); + + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(*pItem); + if (0 != pImpl) + { + pImpl->release(), pImpl = 0; + } +#ifdef _DIRENT_HAVE_D_TYPE + pImpl = new DirectoryItem_Impl(ustrFilePath, pEntry->d_type); +#else + pImpl = new DirectoryItem_Impl(ustrFilePath); +#endif /* _DIRENT_HAVE_D_TYPE */ + *pItem = pImpl; + rtl_uString_release( ustrFilePath ); + + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_getDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_getDirectoryItem( rtl_uString* ustrFileURL, oslDirectoryItem* pItem ) +{ + rtl_uString* ustrSystemPath = NULL; + oslFileError osl_error = osl_File_E_INVAL; + + OSL_ASSERT(ustrFileURL); + OSL_ASSERT(pItem); + + if (0 == ustrFileURL->length || NULL == pItem) + return osl_File_E_INVAL; + + osl_error = osl_getSystemPathFromFileURL_Ex(ustrFileURL, &ustrSystemPath, sal_False); + if (osl_File_E_None != osl_error) + return osl_error; + + osl_systemPathRemoveSeparator(ustrSystemPath); + + if (-1 == access_u(ustrSystemPath, F_OK)) + { + osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); + } + else + { + *pItem = new DirectoryItem_Impl(ustrSystemPath); + } + rtl_uString_release(ustrSystemPath); + + return osl_error; +} + + +/****************************************************************************/ +/* osl_acquireDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item ) +{ + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item); + if (0 == pImpl) + return osl_File_E_INVAL; + + pImpl->acquire(); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_releaseDirectoryItem */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item ) +{ + DirectoryItem_Impl * pImpl = static_cast< DirectoryItem_Impl* >(Item); + if (0 == pImpl) + return osl_File_E_INVAL; + + pImpl->release(); + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_createDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_createDirectory( rtl_uString* ustrDirectoryURL ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrDirectoryURL ); + + /* convert directory url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_createDirectory( path ); +} + +/****************************************************************************/ +/* osl_removeDirectory */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_removeDirectory( rtl_uString* ustrDirectoryURL ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrDirectoryURL ); + + /* convert directory url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_removeDirectory( path ); +} + +/***************************************** + * osl_psz_createDirectory + ****************************************/ + +static oslFileError osl_psz_createDirectory( const sal_Char* pszPath ) +{ + int nRet=0; + int mode = S_IRWXU | S_IRWXG | S_IRWXO; + + nRet = mkdir(pszPath,mode); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_removeDirectory + ****************************************/ + +static oslFileError osl_psz_removeDirectory( const sal_Char* pszPath ) +{ + int nRet=0; + + nRet = rmdir(pszPath); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/****************************************************************************/ +/* osl_createDirectoryPath */ +/****************************************************************************/ + +static int path_make_parent(sal_Unicode* path) +{ + int i = rtl_ustr_lastIndexOfChar(path, '/'); + + if (i > 0) + { + *(path + i) = 0; + return i; + } + else + return 0; +} + +static int create_dir_with_callback( + sal_Unicode* directory_path, + oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, + void* pData) +{ + int mode = S_IRWXU | S_IRWXG | S_IRWXO; + + if (osl::mkdir(directory_path, mode) == 0) + { + if (aDirectoryCreationCallbackFunc) + { + rtl::OUString url; + osl::FileBase::getFileURLFromSystemPath(directory_path, url); + aDirectoryCreationCallbackFunc(pData, url.pData); + } + return 0; + } + return errno; +} + +static oslFileError create_dir_recursively_( + sal_Unicode* dir_path, + oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, + void* pData) +{ + OSL_PRECOND((rtl_ustr_getLength(dir_path) > 0) && ((dir_path + (rtl_ustr_getLength(dir_path) - 1)) != (dir_path + rtl_ustr_lastIndexOfChar(dir_path, '/'))), \ + "Path must not end with a slash"); + + int native_err = create_dir_with_callback( + dir_path, aDirectoryCreationCallbackFunc, pData); + + if (native_err == 0) + return osl_File_E_None; + + if (native_err != ENOENT) + return oslTranslateFileError(OSL_FET_ERROR, native_err); + + // we step back until '/a_dir' at maximum because + // we should get an error unequal ENOENT when + // we try to create 'a_dir' at '/' and would so + // return before + int pos = path_make_parent(dir_path); + + oslFileError osl_error = create_dir_recursively_( + dir_path, aDirectoryCreationCallbackFunc, pData); + + if (osl_File_E_None != osl_error) + return osl_error; + + dir_path[pos] = '/'; + + return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData); +} + +oslFileError SAL_CALL osl_createDirectoryPath( + rtl_uString* aDirectoryUrl, + oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, + void* pData) +{ + if (aDirectoryUrl == NULL) + return osl_File_E_INVAL; + + rtl::OUString sys_path; + oslFileError osl_error = osl_getSystemPathFromFileURL_Ex( + aDirectoryUrl, &sys_path.pData, sal_False); + + if (osl_error != osl_File_E_None) + return osl_error; + + osl::systemPathRemoveSeparator(sys_path); + + // const_cast because sys_path is a local copy which we want to modify inplace instead of + // coyp it into another buffer on the heap again + return create_dir_recursively_(sys_path.pData->buffer, aDirectoryCreationCallbackFunc, pData); +} + +/****************************************************************************** + * + * C-String Function Declarations + * + *****************************************************************************/ + +static oslFileError osl_psz_removeFile(const sal_Char* pszPath); +static oslFileError osl_psz_copyFile(const sal_Char* pszPath, const sal_Char* pszDestPath); +static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath); + + +/****************************************************************************** + * + * Static Module Utility Function Declarations + * + *****************************************************************************/ + +static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists); +static oslFileError oslChangeFileModes(const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID); +static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName); +static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode); +static oslFileError oslDoMoveFile(const sal_Char* pszPath, const sal_Char* pszDestPath); + +/****************************************************************************/ +/* osl_moveFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_moveFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL ) +{ + char srcPath[PATH_MAX]; + char destPath[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrFileURL ); + OSL_ASSERT( ustrDestURL ); + + /* convert source url to system path */ + eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL ); + if( eRet != osl_File_E_None ) + return eRet; + + /* convert destination url to system path */ + eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return oslDoMoveFile( srcPath, destPath ); +} + +/****************************************************************************/ +/* osl_copyFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_copyFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL ) +{ + char srcPath[PATH_MAX]; + char destPath[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrFileURL ); + OSL_ASSERT( ustrDestURL ); + + /* convert source url to system path */ + eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL ); + if( eRet != osl_File_E_None ) + return eRet; + + /* convert destination url to system path */ + eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( destPath, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_copyFile( srcPath, destPath ); +} + +/****************************************************************************/ +/* osl_removeFile */ +/****************************************************************************/ + +oslFileError SAL_CALL osl_removeFile( rtl_uString* ustrFileURL ) +{ + char path[PATH_MAX]; + oslFileError eRet; + + OSL_ASSERT( ustrFileURL ); + + /* convert file url to system path */ + eRet = FileURLToPath( path, PATH_MAX, ustrFileURL ); + if( eRet != osl_File_E_None ) + return eRet; + +#ifdef MACOSX + if ( macxp_resolveAlias( path, PATH_MAX ) != 0 ) + return oslTranslateFileError( OSL_FET_ERROR, errno ); +#endif/* MACOSX */ + + return osl_psz_removeFile( path ); +} + +/****************************************************************************** + * + * Utility Functions + * + *****************************************************************************/ + +/***************************************** + * oslDoMoveFile + ****************************************/ + +static oslFileError oslDoMoveFile( const sal_Char* pszPath, const sal_Char* pszDestPath) +{ + oslFileError tErr=osl_File_E_invalidError; + + tErr = osl_psz_moveFile(pszPath,pszDestPath); + if ( tErr == osl_File_E_None ) + { + return tErr; + } + + if ( tErr != osl_File_E_XDEV ) + { + return tErr; + } + + tErr=osl_psz_copyFile(pszPath,pszDestPath); + + if ( tErr != osl_File_E_None ) + { + oslFileError tErrRemove; + tErrRemove=osl_psz_removeFile(pszDestPath); + return tErr; + } + + tErr=osl_psz_removeFile(pszPath); + + return tErr; +} + +/***************************************** + * osl_psz_removeFile + ****************************************/ +static oslFileError osl_psz_removeFile( const sal_Char* pszPath ) +{ + int nRet=0; + struct stat aStat; + + nRet = lstat(pszPath,&aStat); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + if ( S_ISDIR(aStat.st_mode) ) + { + return osl_File_E_ISDIR; + } + + nRet = unlink(pszPath); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_moveFile + ****************************************/ + +static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath) +{ + + int nRet = 0; + + nRet = rename(pszPath,pszDestPath); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + return osl_File_E_None; +} + +/***************************************** + * osl_psz_copyFile + ****************************************/ + +static oslFileError osl_psz_copyFile( const sal_Char* pszPath, const sal_Char* pszDestPath ) +{ + time_t nAcTime=0; + time_t nModTime=0; + uid_t nUID=0; + gid_t nGID=0; + int nRet=0; + mode_t nMode=0; + struct stat aFileStat; + oslFileError tErr=osl_File_E_invalidError; + size_t nSourceSize=0; + int DestFileExists=1; + + /* mfe: does the source file really exists? */ + nRet = lstat(pszPath,&aFileStat); + + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + /* mfe: we do only copy files here! */ + if ( S_ISDIR(aFileStat.st_mode) ) + { + return osl_File_E_ISDIR; + } + + nSourceSize=(size_t)aFileStat.st_size; + nMode=aFileStat.st_mode; + nAcTime=aFileStat.st_atime; + nModTime=aFileStat.st_mtime; + nUID=aFileStat.st_uid; + nGID=aFileStat.st_gid; + + nRet = stat(pszDestPath,&aFileStat); + if ( nRet < 0 ) + { + nRet=errno; + + if ( nRet == ENOENT ) + { + DestFileExists=0; + } +/* return oslTranslateFileError(nRet);*/ + } + + /* mfe: the destination file must not be a directory! */ + if ( nRet == 0 && S_ISDIR(aFileStat.st_mode) ) + { + return osl_File_E_ISDIR; + } + else + { + /* mfe: file does not exists or is no dir */ + } + + tErr = oslDoCopy(pszPath,pszDestPath,nMode,nSourceSize,DestFileExists); + + if ( tErr != osl_File_E_None ) + { + return tErr; + } + + /* + * mfe: ignore return code + * since only the success of the copy is + * important + */ + oslChangeFileModes(pszDestPath,nMode,nAcTime,nModTime,nUID,nGID); + + return tErr; +} + + +/****************************************************************************** + * + * Utility Functions + * + *****************************************************************************/ + +/***************************************** + * oslDoCopy + ****************************************/ + +#define TMP_DEST_FILE_EXTENSION ".osl-tmp" + +static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists) +{ + int nRet=0; + sal_Char pszTmpDestFile[PATH_MAX]; + size_t size_tmp_dest_buff = sizeof(pszTmpDestFile); + + /* Quick fix for #106048, the whole copy file function seems + to be erroneous anyway and needs to be rewritten. + Besides osl_copyFile is currently not used from OO/SO code. + */ + memset(pszTmpDestFile, 0, size_tmp_dest_buff); + + if ( DestFileExists ) + { + strncpy(pszTmpDestFile, pszDestFileName, size_tmp_dest_buff - 1); + + if ((strlen(pszTmpDestFile) + strlen(TMP_DEST_FILE_EXTENSION)) >= size_tmp_dest_buff) + return osl_File_E_NAMETOOLONG; + + strncat(pszTmpDestFile, TMP_DEST_FILE_EXTENSION, strlen(TMP_DEST_FILE_EXTENSION)); + + /* FIXME: what if pszTmpDestFile already exists? */ + /* with getcanonical??? */ + nRet=rename(pszDestFileName,pszTmpDestFile); + } + + /* mfe: should be S_ISREG */ + if ( !S_ISLNK(nMode) ) + { + /* copy SourceFile to DestFile */ + nRet = oslDoCopyFile(pszSourceFileName,pszDestFileName,nSourceSize, nMode); + } + /* mfe: OK redundant at the moment */ + else if ( S_ISLNK(nMode) ) + { + nRet = oslDoCopyLink(pszSourceFileName,pszDestFileName); + } + else + { + /* mfe: what to do here? */ + nRet=ENOSYS; + } + + if ( nRet > 0 && DestFileExists == 1 ) + { + unlink(pszDestFileName); + rename(pszTmpDestFile,pszDestFileName); + } + + if ( nRet > 0 ) + { + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + if ( DestFileExists == 1 ) + { + unlink(pszTmpDestFile); + } + + return osl_File_E_None; +} + +/***************************************** + * oslChangeFileModes + ****************************************/ + +static oslFileError oslChangeFileModes( const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID) +{ + int nRet=0; + struct utimbuf aTimeBuffer; + + nRet = chmod(pszFileName,nMode); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + aTimeBuffer.actime=nAcTime; + aTimeBuffer.modtime=nModTime; + nRet=utime(pszFileName,&aTimeBuffer); + if ( nRet < 0 ) + { + nRet=errno; + return oslTranslateFileError(OSL_FET_ERROR, nRet); + } + + if ( nUID != getuid() ) + { + nUID=getuid(); + } + + nRet=chown(pszFileName,nUID,nGID); + if ( nRet < 0 ) + { + nRet=errno; + + /* mfe: do not return an error here! */ + /* return oslTranslateFileError(nRet);*/ + } + + return osl_File_E_None; +} + +/***************************************** + * oslDoCopyLink + ****************************************/ + +static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName) +{ + int nRet=0; + + /* mfe: if dest file is symbolic link remove the link and place the file instead (hro says so) */ + /* mfe: if source is a link copy the link and not the file it points to (hro says so) */ + sal_Char pszLinkContent[PATH_MAX]; + + pszLinkContent[0] = '\0'; + + nRet = readlink(pszSourceFileName,pszLinkContent,PATH_MAX); + + if ( nRet < 0 ) + { + nRet=errno; + return nRet; + } + else + pszLinkContent[ nRet ] = 0; + + nRet = symlink(pszLinkContent,pszDestFileName); + + if ( nRet < 0 ) + { + nRet=errno; + return nRet; + } + + return 0; +} + +/***************************************** + * oslDoCopyFile + ****************************************/ + +static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode) +{ + int SourceFileFD=0; + int DestFileFD=0; + int nRet=0; + + SourceFileFD=open(pszSourceFileName,O_RDONLY); + if ( SourceFileFD < 0 ) + { + nRet=errno; + return nRet; + } + + DestFileFD=open(pszDestFileName, O_WRONLY | O_CREAT, mode); + + if ( DestFileFD < 0 ) + { + nRet=errno; + close(SourceFileFD); + return nRet; + } + + /* HACK: because memory mapping fails on various + platforms if the size of the source file is 0 byte */ + if (0 == nSourceSize) + { + close(SourceFileFD); + close(DestFileFD); + return 0; + } + + // read and lseek are used to check the possibility to access the data + // not a nice solution, but it allows to avoid a crash in case it is an opened samba file + // generally, reading of one byte should not affect the performance + char nCh; + if ( 1 != read( SourceFileFD, &nCh, 1 ) + || -1 == lseek( SourceFileFD, 0, SEEK_SET ) ) + { + nRet = errno; + close( SourceFileFD ); + close( DestFileFD ); + return nRet; + } + + size_t nWritten = 0; + size_t nRemains = nSourceSize; + + /* mmap file -- open dest file -- write -- fsync it at the end */ + void* pSourceFile = mmap( 0, nSourceSize, PROT_READ, MAP_SHARED, SourceFileFD, 0 ); + if ( pSourceFile != MAP_FAILED ) + { + nWritten = write( DestFileFD, pSourceFile, nSourceSize ); + nRemains -= nWritten; + munmap( (char*)pSourceFile, nSourceSize ); + } + + if ( nRemains ) + { + /* mmap has problems, try the direct streaming */ + char pBuffer[32000]; + size_t nRead = 0; + + nRemains = nSourceSize; + + if ( -1 != lseek( SourceFileFD, 0, SEEK_SET ) + && -1 != lseek( DestFileFD, 0, SEEK_SET ) ) + { + do + { + nRead = 0; + nWritten = 0; + + size_t nToRead = std::min( (size_t)32000, nRemains ); + nRead = read( SourceFileFD, pBuffer, nToRead ); + if ( (size_t)-1 != nRead ) + nWritten = write( DestFileFD, pBuffer, nRead ); + + if ( (size_t)-1 != nWritten ) + nRemains -= nWritten; + } + while( nRemains && (size_t)-1 != nRead && nRead == nWritten ); + } + } + + if ( nRemains ) + { + if ( errno ) + nRet = errno; + else + nRet = ENOSPC; + } + + close( SourceFileFD ); + if ( close( DestFileFD ) == -1 && nRet == 0 ) + nRet = errno; + + return nRet; +} + |