LibreOffice Module tools (master) 1
strmwnt.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20// TODO: StreamMode <-> AllocateMemory
21
22#include <string.h>
23#include <limits.h>
24
25#ifdef _WIN32
26#if !defined WIN32_LEAN_AND_MEAN
27# define WIN32_LEAN_AND_MEAN
28#endif
29#include <windows.h>
30#endif
31
32#include <osl/thread.h>
33#include <tools/stream.hxx>
35
36#include <osl/file.hxx>
37using namespace osl;
38
39static ErrCode GetSvError( DWORD nWntError )
40{
41 static struct { DWORD wnt; ErrCode sv; } errArr[] =
42 {
43 { ERROR_SUCCESS, ERRCODE_NONE },
44 { ERROR_ACCESS_DENIED, SVSTREAM_ACCESS_DENIED },
45 { ERROR_ACCOUNT_DISABLED, SVSTREAM_ACCESS_DENIED },
46 { ERROR_ACCOUNT_EXPIRED, SVSTREAM_ACCESS_DENIED },
47 { ERROR_ACCOUNT_RESTRICTION, SVSTREAM_ACCESS_DENIED },
48 { ERROR_ATOMIC_LOCKS_NOT_SUPPORTED, SVSTREAM_INVALID_PARAMETER },
49 { ERROR_BAD_PATHNAME, SVSTREAM_PATH_NOT_FOUND },
50 // Filename too long
51 { ERROR_BUFFER_OVERFLOW, SVSTREAM_INVALID_PARAMETER },
52 { ERROR_DIRECTORY, SVSTREAM_INVALID_PARAMETER },
53 { ERROR_DRIVE_LOCKED, SVSTREAM_LOCKING_VIOLATION },
54 { ERROR_FILE_NOT_FOUND, SVSTREAM_FILE_NOT_FOUND },
55 { ERROR_FILENAME_EXCED_RANGE, SVSTREAM_INVALID_PARAMETER },
56 { ERROR_INVALID_ACCESS, SVSTREAM_INVALID_ACCESS },
57 { ERROR_INVALID_DRIVE, SVSTREAM_PATH_NOT_FOUND },
58 { ERROR_INVALID_HANDLE, SVSTREAM_INVALID_HANDLE },
59 { ERROR_INVALID_NAME, SVSTREAM_PATH_NOT_FOUND },
60 { ERROR_INVALID_PARAMETER, SVSTREAM_INVALID_PARAMETER },
61 { ERROR_IS_SUBST_PATH, SVSTREAM_INVALID_PARAMETER },
62 { ERROR_IS_SUBST_TARGET, SVSTREAM_INVALID_PARAMETER },
63 { ERROR_LOCK_FAILED, SVSTREAM_LOCKING_VIOLATION },
64 { ERROR_LOCK_VIOLATION, SVSTREAM_LOCKING_VIOLATION },
65 { ERROR_NEGATIVE_SEEK, SVSTREAM_SEEK_ERROR },
66 { ERROR_PATH_NOT_FOUND, SVSTREAM_PATH_NOT_FOUND },
67 { ERROR_READ_FAULT, SVSTREAM_READ_ERROR },
68 { ERROR_SEEK, SVSTREAM_SEEK_ERROR },
69 { ERROR_SEEK_ON_DEVICE, SVSTREAM_SEEK_ERROR },
70 { ERROR_SHARING_BUFFER_EXCEEDED,SVSTREAM_SHARE_BUFF_EXCEEDED },
71 { ERROR_SHARING_PAUSED, SVSTREAM_SHARING_VIOLATION },
72 { ERROR_SHARING_VIOLATION, SVSTREAM_SHARING_VIOLATION },
73 { ERROR_TOO_MANY_OPEN_FILES, SVSTREAM_TOO_MANY_OPEN_FILES },
74 { ERROR_WRITE_FAULT, SVSTREAM_WRITE_ERROR },
75 { ERROR_WRITE_PROTECT, SVSTREAM_ACCESS_DENIED },
76 { ERROR_DISK_FULL, SVSTREAM_DISK_FULL },
77
78 { DWORD(0xFFFFFFFF), SVSTREAM_GENERALERROR }
79 };
80
81 ErrCode nRetVal = SVSTREAM_GENERALERROR; // default error
82 int i=0;
83 do
84 {
85 if( errArr[i].wnt == nWntError )
86 {
87 nRetVal = errArr[i].sv;
88 break;
89 }
90 i++;
91 } while( errArr[i].wnt != DWORD(0xFFFFFFFF) );
92 return nRetVal;
93}
94
95SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nMode )
96{
97 bIsOpen = false;
98 nLockCounter = 0;
99 m_isWritable = false;
100
101 SetBufferSize( 8192 );
102 // convert URL to SystemPath, if necessary
103 OUString aFileName;
104
105 if ( FileBase::getSystemPathFromFileURL( rFileName, aFileName ) != FileBase::E_None )
106 aFileName = rFileName;
107 Open( aFileName, nMode );
108}
109
111{
112 bIsOpen = false;
113 nLockCounter = 0;
114 m_isWritable = false;
115
116 SetBufferSize( 8192 );
117}
118
120{
121 Close();
122}
123
125std::size_t SvFileStream::GetData( void* pData, std::size_t nSize )
126{
127 DWORD nCount = 0;
128 if( IsOpen() )
129 {
130 bool bResult = ReadFile(mxFileHandle,pData,nSize,&nCount,nullptr);
131 if( !bResult )
132 {
133 std::size_t nTestError = GetLastError();
134 SetError(::GetSvError( nTestError ) );
135 }
136 }
137 return nCount;
138}
139
140std::size_t SvFileStream::PutData( const void* pData, std::size_t nSize )
141{
142 DWORD nCount = 0;
143 if( IsOpen() )
144 {
145 if(!WriteFile(mxFileHandle,pData,nSize,&nCount,nullptr))
146 SetError(::GetSvError( GetLastError() ) );
147 }
148 return nCount;
149}
150
151sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos)
152{
153 // check if a truncated STREAM_SEEK_TO_END was passed
154 assert(nPos != SAL_MAX_UINT32);
155 LARGE_INTEGER nNewPos, nActPos;
156 nNewPos.QuadPart = 0;
157 nActPos.QuadPart = nPos;
158 bool result = false;
159 if( IsOpen() )
160 {
161 if( nPos != STREAM_SEEK_TO_END )
162 {
163 result = SetFilePointerEx(mxFileHandle, nActPos, &nNewPos, FILE_BEGIN);
164 }
165 else
166 {
167 result = SetFilePointerEx(mxFileHandle, nNewPos, &nNewPos, FILE_END);
168 }
169 if (!result)
170 {
171 SetError(::GetSvError(GetLastError()));
172 return 0;
173 }
174 }
175 else
176 SetError( SVSTREAM_GENERALERROR );
177 return static_cast<sal_uInt64>(nNewPos.QuadPart);
178}
179
181{
182 if( IsOpen() )
183 {
184 if( !FlushFileBuffers(mxFileHandle) )
185 SetError(::GetSvError(GetLastError()));
186 }
187}
188
190{
191 bool bRetVal = false;
192 if( !nLockCounter )
193 {
194 if( IsOpen() )
195 {
196 bRetVal = ::LockFile(mxFileHandle,0L,0L,LONG_MAX,0L );
197 if( bRetVal )
198 {
199 nLockCounter = 1;
200 }
201 else
202 SetError(::GetSvError(GetLastError()));
203 }
204 }
205 else
206 {
207 nLockCounter++;
208 bRetVal = true;
209 }
210 return bRetVal;
211}
212
214{
215 if( nLockCounter > 0)
216 {
217 if( nLockCounter == 1)
218 {
219 if( IsOpen() )
220 {
221 if( ::UnlockFile(mxFileHandle,0L,0L,LONG_MAX,0L ) )
222 {
223 nLockCounter = 0;
224 }
225 else
226 SetError(::GetSvError(GetLastError()));
227 }
228 }
229 else
230 {
231 nLockCounter--;
232 }
233 }
234}
235
236/*
237 NOCREATE TRUNC NT-Action
238 ----------------------------------------------
239 0 (Create) 0 OPEN_ALWAYS
240 0 (Create) 1 CREATE_ALWAYS
241 1 0 OPEN_EXISTING
242 1 1 TRUNCATE_EXISTING
243*/
244void SvFileStream::Open( const OUString& rFilename, StreamMode nMode )
245{
246 OUString aParsedFilename(rFilename);
247
248 SetLastError( ERROR_SUCCESS );
249 Close();
251
252 m_eStreamMode = nMode;
253 m_eStreamMode &= ~StreamMode::TRUNC; // don't truncate on reopen
254
255 aFilename = aParsedFilename;
256 SetLastError( ERROR_SUCCESS ); // might be changed by Redirector
257
258 DWORD nOpenAction;
259 DWORD nShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
260 DWORD nAccessMode = 0;
261 UINT nOldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX );
262
263 if( nMode & StreamMode::SHARE_DENYREAD)
264 nShareMode &= ~FILE_SHARE_READ;
265
266 if( nMode & StreamMode::SHARE_DENYWRITE)
267 nShareMode &= ~FILE_SHARE_WRITE;
268
269 if( nMode & StreamMode::SHARE_DENYALL)
270 nShareMode = 0;
271
272 if( nMode & StreamMode::READ )
273 nAccessMode |= GENERIC_READ;
274 if( nMode & StreamMode::WRITE )
275 nAccessMode |= GENERIC_WRITE;
276
277 if( nAccessMode == GENERIC_READ ) // ReadOnly ?
278 nMode |= StreamMode::NOCREATE; // Don't create if readonly
279
280 // Assignment based on true/false table above
281 if( !(nMode & StreamMode::NOCREATE) )
282 {
283 if( nMode & StreamMode::TRUNC )
284 nOpenAction = CREATE_ALWAYS;
285 else
286 nOpenAction = OPEN_ALWAYS;
287 }
288 else
289 {
290 if( nMode & StreamMode::TRUNC )
291 nOpenAction = TRUNCATE_EXISTING;
292 else
293 nOpenAction = OPEN_EXISTING;
294 }
295
296 DWORD nAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
297
298 if ( nMode & StreamMode::TEMPORARY )
299 nAttributes |= FILE_ATTRIBUTE_TEMPORARY;
300 if ( nMode & StreamMode::DELETE_ON_CLOSE )
301 nAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
302
303 mxFileHandle = CreateFileW(
304 o3tl::toW(aFilename.getStr()),
305 nAccessMode,
306 nShareMode,
307 nullptr,
308 nOpenAction,
309 nAttributes,
310 nullptr
311 );
312
313 if( mxFileHandle!=INVALID_HANDLE_VALUE && (
314 // Did Create Always overwrite a file?
315 GetLastError() == ERROR_ALREADY_EXISTS ||
316 // Did Create Always open a new file?
317 GetLastError() == ERROR_FILE_NOT_FOUND ))
318 {
319 // If so, no error
320 if( nOpenAction == OPEN_ALWAYS || nOpenAction == CREATE_ALWAYS )
321 SetLastError( ERROR_SUCCESS );
322 }
323
324 // Otherwise, determine if we're allowed to read
325 if( (mxFileHandle==INVALID_HANDLE_VALUE) &&
326 (nAccessMode & GENERIC_WRITE))
327 {
328 ErrCode nErr = ::GetSvError( GetLastError() );
329 if(nErr==SVSTREAM_ACCESS_DENIED || nErr==SVSTREAM_SHARING_VIOLATION)
330 {
331 nMode &= ~StreamMode::WRITE;
332 nAccessMode = GENERIC_READ;
333 // OV, 28.1.97: Win32 sets file to length 0
334 // if Openaction is CREATE_ALWAYS
335 nOpenAction = OPEN_EXISTING;
336 SetLastError( ERROR_SUCCESS );
337 mxFileHandle = CreateFileW(
338 o3tl::toW(aFilename.getStr()),
339 GENERIC_READ,
340 nShareMode,
341 nullptr,
342 nOpenAction,
343 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
344 nullptr
345 );
346 if( GetLastError() == ERROR_ALREADY_EXISTS )
347 SetLastError( ERROR_SUCCESS );
348 }
349 }
350
351 if( GetLastError() != ERROR_SUCCESS )
352 {
353 bIsOpen = false;
354 SetError(::GetSvError( GetLastError() ) );
355 }
356 else
357 {
358 bIsOpen = true;
359 // pInstanceData->bIsEof = false;
360 if( nAccessMode & GENERIC_WRITE )
361 m_isWritable = true;
362 }
363 SetErrorMode( nOldErrorMode );
364}
365
367{
368 if( IsOpen() )
369 {
370 if( nLockCounter )
371 {
372 nLockCounter = 1;
373 UnlockFile();
374 }
375 FlushBuffer();
376 CloseHandle( mxFileHandle );
377 }
378 bIsOpen = false;
379 nLockCounter= 0;
380 m_isWritable = false;
383}
384
387{
389}
390
391void SvFileStream::SetSize(sal_uInt64 const nSize)
392{
393
394 if( IsOpen() )
395 {
396 bool bError = false;
397 HANDLE hFile = mxFileHandle;
398 DWORD const nOld = SetFilePointer( hFile, 0L, nullptr, FILE_CURRENT );
399 if( nOld != 0xffffffff )
400 {
401 if( SetFilePointer(hFile,nSize,nullptr,FILE_BEGIN ) != 0xffffffff)
402 {
403 bool bSucc = SetEndOfFile( hFile );
404 if( !bSucc )
405 bError = true;
406 }
407 if( SetFilePointer( hFile,nOld,nullptr,FILE_BEGIN ) == 0xffffffff)
408 bError = true;
409 }
410 if( bError )
411 SetError(::GetSvError( GetLastError() ) );
412 }
413}
414
415/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsOpen() const
Definition: stream.hxx:618
bool LockFile()
Definition: strmunx.cxx:285
OUString aFilename
Definition: stream.hxx:593
virtual std::size_t GetData(void *pData, std::size_t nSize) override
Does not check for EOF, makes isEof callable.
Definition: strmunx.cxx:215
virtual void ResetError() override
set filepointer to beginning of file
Definition: strmunx.cxx:467
virtual void FlushData() override
Definition: strmunx.cxx:278
void Open(const OUString &rFileName, StreamMode eOpenMode)
Definition: strmunx.cxx:342
void * mxFileHandle
Definition: stream.hxx:589
virtual ~SvFileStream() override
Definition: strmunx.cxx:210
void Close()
Definition: strmunx.cxx:448
void UnlockFile()
Definition: strmunx.cxx:334
bool bIsOpen
Definition: stream.hxx:594
virtual void SetSize(sal_uInt64 nSize) override
Definition: strmunx.cxx:472
virtual sal_uInt64 SeekPos(sal_uInt64 nPos) override
Definition: strmunx.cxx:251
virtual std::size_t PutData(const void *pData, std::size_t nSize) override
Definition: strmunx.cxx:232
bool m_isWritable
Definition: stream.hxx:182
SAL_DLLPRIVATE void ClearBuffer()
Definition: stream.cxx:406
void SetBufferSize(sal_uInt16 m_nBufSize)
Definition: stream.cxx:380
SAL_DLLPRIVATE void ClearError()
Definition: stream.cxx:350
StreamMode m_eStreamMode
Definition: stream.hxx:181
void SetError(ErrCode nErrorCode)
Definition: stream.cxx:356
void FlushBuffer()
If we have data in our internal buffers, write them out.
Definition: stream.cxx:1101
int nCount
#define SVSTREAM_WRITE_ERROR
#define SVSTREAM_SHARING_VIOLATION
#define SVSTREAM_TOO_MANY_OPEN_FILES
#define SVSTREAM_ACCESS_DENIED
#define SVSTREAM_INVALID_PARAMETER
#define SVSTREAM_PATH_NOT_FOUND
#define SVSTREAM_LOCKING_VIOLATION
#define SVSTREAM_SEEK_ERROR
#define SVSTREAM_INVALID_ACCESS
#define SVSTREAM_SHARE_BUFF_EXCEEDED
#define SVSTREAM_DISK_FULL
#define SVSTREAM_INVALID_HANDLE
#define SVSTREAM_GENERALERROR
#define ERRCODE_NONE
#define SVSTREAM_FILE_NOT_FOUND
#define SVSTREAM_READ_ERROR
sal_uInt16 nPos
int i
sal_Int16 nAttributes
#define STREAM_SEEK_TO_END
Definition: stream.hxx:73
StreamMode
Definition: stream.hxx:46
@ READ
allow read accesses
@ TEMPORARY
temporary file attribute (Windows-only)
@ TRUNC
Truncate existing file to zero length.
@ NOCREATE
1 == Don't create file
@ WRITE
allow write accesses
@ DELETE_ON_CLOSE
only for temporary files (Windows-only)
static ErrCode GetSvError(DWORD nWntError)
Definition: strmwnt.cxx:39
Any result