blob: aa1aa51d35b3426aa4dc3614fb757a150e2015cb [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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((0 != ustrFileURL) && (0 != pItem));
if ((0 == ustrFileURL) || (0 == ustrFileURL->length) || (0 == 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;
}
size_t nWritten = 0;
size_t nRemains = nSourceSize;
if ( nRemains )
{
/* mmap has problems, try the direct streaming */
char pBuffer[0x8000];
size_t nRead = 0;
nRemains = nSourceSize;
do
{
nRead = 0;
nWritten = 0;
size_t nToRead = std::min( (size_t)0x8000, 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;
}