415 lines
12 KiB
C++
415 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* 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 .
|
|
*/
|
|
|
|
// TODO: StreamMode <-> AllocateMemory
|
|
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#ifdef _WIN32
|
|
#if !defined WIN32_LEAN_AND_MEAN
|
|
# define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include <osl/thread.h>
|
|
#include <tools/stream.hxx>
|
|
#include <o3tl/char16_t2wchar_t.hxx>
|
|
|
|
#include <osl/file.hxx>
|
|
using namespace osl;
|
|
|
|
static ErrCode GetSvError( DWORD nWntError )
|
|
{
|
|
static struct { DWORD wnt; ErrCode sv; } errArr[] =
|
|
{
|
|
{ ERROR_SUCCESS, ERRCODE_NONE },
|
|
{ ERROR_ACCESS_DENIED, SVSTREAM_ACCESS_DENIED },
|
|
{ ERROR_ACCOUNT_DISABLED, SVSTREAM_ACCESS_DENIED },
|
|
{ ERROR_ACCOUNT_EXPIRED, SVSTREAM_ACCESS_DENIED },
|
|
{ ERROR_ACCOUNT_RESTRICTION, SVSTREAM_ACCESS_DENIED },
|
|
{ ERROR_ATOMIC_LOCKS_NOT_SUPPORTED, SVSTREAM_INVALID_PARAMETER },
|
|
{ ERROR_BAD_PATHNAME, SVSTREAM_PATH_NOT_FOUND },
|
|
// Filename too long
|
|
{ ERROR_BUFFER_OVERFLOW, SVSTREAM_INVALID_PARAMETER },
|
|
{ ERROR_DIRECTORY, SVSTREAM_INVALID_PARAMETER },
|
|
{ ERROR_DRIVE_LOCKED, SVSTREAM_LOCKING_VIOLATION },
|
|
{ ERROR_FILE_NOT_FOUND, SVSTREAM_FILE_NOT_FOUND },
|
|
{ ERROR_FILENAME_EXCED_RANGE, SVSTREAM_INVALID_PARAMETER },
|
|
{ ERROR_INVALID_ACCESS, SVSTREAM_INVALID_ACCESS },
|
|
{ ERROR_INVALID_DRIVE, SVSTREAM_PATH_NOT_FOUND },
|
|
{ ERROR_INVALID_HANDLE, SVSTREAM_INVALID_HANDLE },
|
|
{ ERROR_INVALID_NAME, SVSTREAM_PATH_NOT_FOUND },
|
|
{ ERROR_INVALID_PARAMETER, SVSTREAM_INVALID_PARAMETER },
|
|
{ ERROR_IS_SUBST_PATH, SVSTREAM_INVALID_PARAMETER },
|
|
{ ERROR_IS_SUBST_TARGET, SVSTREAM_INVALID_PARAMETER },
|
|
{ ERROR_LOCK_FAILED, SVSTREAM_LOCKING_VIOLATION },
|
|
{ ERROR_LOCK_VIOLATION, SVSTREAM_LOCKING_VIOLATION },
|
|
{ ERROR_NEGATIVE_SEEK, SVSTREAM_SEEK_ERROR },
|
|
{ ERROR_PATH_NOT_FOUND, SVSTREAM_PATH_NOT_FOUND },
|
|
{ ERROR_READ_FAULT, SVSTREAM_READ_ERROR },
|
|
{ ERROR_SEEK, SVSTREAM_SEEK_ERROR },
|
|
{ ERROR_SEEK_ON_DEVICE, SVSTREAM_SEEK_ERROR },
|
|
{ ERROR_SHARING_BUFFER_EXCEEDED,SVSTREAM_SHARE_BUFF_EXCEEDED },
|
|
{ ERROR_SHARING_PAUSED, SVSTREAM_SHARING_VIOLATION },
|
|
{ ERROR_SHARING_VIOLATION, SVSTREAM_SHARING_VIOLATION },
|
|
{ ERROR_TOO_MANY_OPEN_FILES, SVSTREAM_TOO_MANY_OPEN_FILES },
|
|
{ ERROR_WRITE_FAULT, SVSTREAM_WRITE_ERROR },
|
|
{ ERROR_WRITE_PROTECT, SVSTREAM_ACCESS_DENIED },
|
|
{ ERROR_DISK_FULL, SVSTREAM_DISK_FULL },
|
|
|
|
{ DWORD(0xFFFFFFFF), SVSTREAM_GENERALERROR }
|
|
};
|
|
|
|
ErrCode nRetVal = SVSTREAM_GENERALERROR; // default error
|
|
int i=0;
|
|
do
|
|
{
|
|
if( errArr[i].wnt == nWntError )
|
|
{
|
|
nRetVal = errArr[i].sv;
|
|
break;
|
|
}
|
|
i++;
|
|
} while( errArr[i].wnt != DWORD(0xFFFFFFFF) );
|
|
return nRetVal;
|
|
}
|
|
|
|
SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nMode )
|
|
{
|
|
bIsOpen = false;
|
|
nLockCounter = 0;
|
|
m_isWritable = false;
|
|
|
|
SetBufferSize( 8192 );
|
|
// convert URL to SystemPath, if necessary
|
|
OUString aFileName;
|
|
|
|
if ( FileBase::getSystemPathFromFileURL( rFileName, aFileName ) != FileBase::E_None )
|
|
aFileName = rFileName;
|
|
Open( aFileName, nMode );
|
|
}
|
|
|
|
SvFileStream::SvFileStream()
|
|
{
|
|
bIsOpen = false;
|
|
nLockCounter = 0;
|
|
m_isWritable = false;
|
|
|
|
SetBufferSize( 8192 );
|
|
}
|
|
|
|
SvFileStream::~SvFileStream()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
/// Does not check for EOF, makes isEof callable
|
|
std::size_t SvFileStream::GetData( void* pData, std::size_t nSize )
|
|
{
|
|
DWORD nCount = 0;
|
|
if( IsOpen() )
|
|
{
|
|
bool bResult = ReadFile(mxFileHandle,pData,nSize,&nCount,nullptr);
|
|
if( !bResult )
|
|
{
|
|
std::size_t nTestError = GetLastError();
|
|
SetError(::GetSvError( nTestError ) );
|
|
}
|
|
}
|
|
return nCount;
|
|
}
|
|
|
|
std::size_t SvFileStream::PutData( const void* pData, std::size_t nSize )
|
|
{
|
|
DWORD nCount = 0;
|
|
if( IsOpen() )
|
|
{
|
|
if(!WriteFile(mxFileHandle,pData,nSize,&nCount,nullptr))
|
|
SetError(::GetSvError( GetLastError() ) );
|
|
}
|
|
return nCount;
|
|
}
|
|
|
|
sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos)
|
|
{
|
|
// check if a truncated STREAM_SEEK_TO_END was passed
|
|
assert(nPos != SAL_MAX_UINT32);
|
|
LARGE_INTEGER nNewPos, nActPos;
|
|
nNewPos.QuadPart = 0;
|
|
nActPos.QuadPart = nPos;
|
|
bool result = false;
|
|
if( IsOpen() )
|
|
{
|
|
if( nPos != STREAM_SEEK_TO_END )
|
|
{
|
|
result = SetFilePointerEx(mxFileHandle, nActPos, &nNewPos, FILE_BEGIN);
|
|
}
|
|
else
|
|
{
|
|
result = SetFilePointerEx(mxFileHandle, nNewPos, &nNewPos, FILE_END);
|
|
}
|
|
if (!result)
|
|
{
|
|
SetError(::GetSvError(GetLastError()));
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
SetError( SVSTREAM_GENERALERROR );
|
|
return static_cast<sal_uInt64>(nNewPos.QuadPart);
|
|
}
|
|
|
|
void SvFileStream::FlushData()
|
|
{
|
|
if( IsOpen() )
|
|
{
|
|
if( !FlushFileBuffers(mxFileHandle) )
|
|
SetError(::GetSvError(GetLastError()));
|
|
}
|
|
}
|
|
|
|
bool SvFileStream::LockFile()
|
|
{
|
|
bool bRetVal = false;
|
|
if( !nLockCounter )
|
|
{
|
|
if( IsOpen() )
|
|
{
|
|
bRetVal = ::LockFile(mxFileHandle,0L,0L,LONG_MAX,0L );
|
|
if( bRetVal )
|
|
{
|
|
nLockCounter = 1;
|
|
}
|
|
else
|
|
SetError(::GetSvError(GetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nLockCounter++;
|
|
bRetVal = true;
|
|
}
|
|
return bRetVal;
|
|
}
|
|
|
|
void SvFileStream::UnlockFile()
|
|
{
|
|
if( nLockCounter > 0)
|
|
{
|
|
if( nLockCounter == 1)
|
|
{
|
|
if( IsOpen() )
|
|
{
|
|
if( ::UnlockFile(mxFileHandle,0L,0L,LONG_MAX,0L ) )
|
|
{
|
|
nLockCounter = 0;
|
|
}
|
|
else
|
|
SetError(::GetSvError(GetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nLockCounter--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
NOCREATE TRUNC NT-Action
|
|
----------------------------------------------
|
|
0 (Create) 0 OPEN_ALWAYS
|
|
0 (Create) 1 CREATE_ALWAYS
|
|
1 0 OPEN_EXISTING
|
|
1 1 TRUNCATE_EXISTING
|
|
*/
|
|
void SvFileStream::Open( const OUString& rFilename, StreamMode nMode )
|
|
{
|
|
OUString aParsedFilename(rFilename);
|
|
|
|
SetLastError( ERROR_SUCCESS );
|
|
Close();
|
|
SvStream::ClearBuffer();
|
|
|
|
m_eStreamMode = nMode;
|
|
m_eStreamMode &= ~StreamMode::TRUNC; // don't truncate on reopen
|
|
|
|
aFilename = aParsedFilename;
|
|
SetLastError( ERROR_SUCCESS ); // might be changed by Redirector
|
|
|
|
DWORD nOpenAction;
|
|
DWORD nShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
DWORD nAccessMode = 0;
|
|
UINT nOldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX );
|
|
|
|
if( nMode & StreamMode::SHARE_DENYREAD)
|
|
nShareMode &= ~FILE_SHARE_READ;
|
|
|
|
if( nMode & StreamMode::SHARE_DENYWRITE)
|
|
nShareMode &= ~FILE_SHARE_WRITE;
|
|
|
|
if( nMode & StreamMode::SHARE_DENYALL)
|
|
nShareMode = 0;
|
|
|
|
if( nMode & StreamMode::READ )
|
|
nAccessMode |= GENERIC_READ;
|
|
if( nMode & StreamMode::WRITE )
|
|
nAccessMode |= GENERIC_WRITE;
|
|
|
|
if( nAccessMode == GENERIC_READ ) // ReadOnly ?
|
|
nMode |= StreamMode::NOCREATE; // Don't create if readonly
|
|
|
|
// Assignment based on true/false table above
|
|
if( !(nMode & StreamMode::NOCREATE) )
|
|
{
|
|
if( nMode & StreamMode::TRUNC )
|
|
nOpenAction = CREATE_ALWAYS;
|
|
else
|
|
nOpenAction = OPEN_ALWAYS;
|
|
}
|
|
else
|
|
{
|
|
if( nMode & StreamMode::TRUNC )
|
|
nOpenAction = TRUNCATE_EXISTING;
|
|
else
|
|
nOpenAction = OPEN_EXISTING;
|
|
}
|
|
|
|
DWORD nAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
|
|
|
|
if ( nMode & StreamMode::TEMPORARY )
|
|
nAttributes |= FILE_ATTRIBUTE_TEMPORARY;
|
|
if ( nMode & StreamMode::DELETE_ON_CLOSE )
|
|
nAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
|
|
|
|
mxFileHandle = CreateFileW(
|
|
o3tl::toW(aFilename.getStr()),
|
|
nAccessMode,
|
|
nShareMode,
|
|
nullptr,
|
|
nOpenAction,
|
|
nAttributes,
|
|
nullptr
|
|
);
|
|
|
|
if( mxFileHandle!=INVALID_HANDLE_VALUE && (
|
|
// Did Create Always overwrite a file?
|
|
GetLastError() == ERROR_ALREADY_EXISTS ||
|
|
// Did Create Always open a new file?
|
|
GetLastError() == ERROR_FILE_NOT_FOUND ))
|
|
{
|
|
// If so, no error
|
|
if( nOpenAction == OPEN_ALWAYS || nOpenAction == CREATE_ALWAYS )
|
|
SetLastError( ERROR_SUCCESS );
|
|
}
|
|
|
|
// Otherwise, determine if we're allowed to read
|
|
if( (mxFileHandle==INVALID_HANDLE_VALUE) &&
|
|
(nAccessMode & GENERIC_WRITE))
|
|
{
|
|
ErrCode nErr = ::GetSvError( GetLastError() );
|
|
if(nErr==SVSTREAM_ACCESS_DENIED || nErr==SVSTREAM_SHARING_VIOLATION)
|
|
{
|
|
nMode &= ~StreamMode::WRITE;
|
|
nAccessMode = GENERIC_READ;
|
|
// OV, 28.1.97: Win32 sets file to length 0
|
|
// if Openaction is CREATE_ALWAYS
|
|
nOpenAction = OPEN_EXISTING;
|
|
SetLastError( ERROR_SUCCESS );
|
|
mxFileHandle = CreateFileW(
|
|
o3tl::toW(aFilename.getStr()),
|
|
GENERIC_READ,
|
|
nShareMode,
|
|
nullptr,
|
|
nOpenAction,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
|
nullptr
|
|
);
|
|
if( GetLastError() == ERROR_ALREADY_EXISTS )
|
|
SetLastError( ERROR_SUCCESS );
|
|
}
|
|
}
|
|
|
|
if( GetLastError() != ERROR_SUCCESS )
|
|
{
|
|
bIsOpen = false;
|
|
SetError(::GetSvError( GetLastError() ) );
|
|
}
|
|
else
|
|
{
|
|
bIsOpen = true;
|
|
// pInstanceData->bIsEof = false;
|
|
if( nAccessMode & GENERIC_WRITE )
|
|
m_isWritable = true;
|
|
}
|
|
SetErrorMode( nOldErrorMode );
|
|
}
|
|
|
|
void SvFileStream::Close()
|
|
{
|
|
if( IsOpen() )
|
|
{
|
|
if( nLockCounter )
|
|
{
|
|
nLockCounter = 1;
|
|
UnlockFile();
|
|
}
|
|
FlushBuffer();
|
|
CloseHandle( mxFileHandle );
|
|
}
|
|
bIsOpen = false;
|
|
nLockCounter= 0;
|
|
m_isWritable = false;
|
|
SvStream::ClearBuffer();
|
|
SvStream::ClearError();
|
|
}
|
|
|
|
/// Reset filepointer to beginning of file
|
|
void SvFileStream::ResetError()
|
|
{
|
|
SvStream::ClearError();
|
|
}
|
|
|
|
void SvFileStream::SetSize(sal_uInt64 const nSize)
|
|
{
|
|
|
|
if( IsOpen() )
|
|
{
|
|
bool bError = false;
|
|
HANDLE hFile = mxFileHandle;
|
|
DWORD const nOld = SetFilePointer( hFile, 0L, nullptr, FILE_CURRENT );
|
|
if( nOld != 0xffffffff )
|
|
{
|
|
if( SetFilePointer(hFile,nSize,nullptr,FILE_BEGIN ) != 0xffffffff)
|
|
{
|
|
bool bSucc = SetEndOfFile( hFile );
|
|
if( !bSucc )
|
|
bError = true;
|
|
}
|
|
if( SetFilePointer( hFile,nOld,nullptr,FILE_BEGIN ) == 0xffffffff)
|
|
bError = true;
|
|
}
|
|
if( bError )
|
|
SetError(::GetSvError( GetLastError() ) );
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|