kernel32: Fix typo in enum_locale_ex_proc.
[wine.git] / dlls / ole32 / filelockbytes.c
blob605b5df55472aaf8ca626a6255ffe5d4ecc80515
1 /******************************************************************************
3 * File-based ILockBytes implementation
5 * Copyright 1999 Thuy Nguyen
6 * Copyright 2010 Vincent Povirk for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <limits.h>
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winuser.h"
37 #include "winerror.h"
38 #include "objbase.h"
39 #include "ole2.h"
41 #include "storage32.h"
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(storage);
48 typedef struct FileLockBytesImpl
50 ILockBytes ILockBytes_iface;
51 LONG ref;
52 HANDLE hfile;
53 DWORD flProtect;
54 LPWSTR pwcsName;
55 } FileLockBytesImpl;
57 static const ILockBytesVtbl FileLockBytesImpl_Vtbl;
59 static inline FileLockBytesImpl *impl_from_ILockBytes(ILockBytes *iface)
61 return CONTAINING_RECORD(iface, FileLockBytesImpl, ILockBytes_iface);
64 /***********************************************************
65 * Prototypes for private methods
68 /* Note that this evaluates a and b multiple times, so don't
69 * pass expressions with side effects. */
70 #define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
72 /****************************************************************************
73 * GetProtectMode
75 * This function will return a protection mode flag for a file-mapping object
76 * from the open flags of a file.
78 static DWORD GetProtectMode(DWORD openFlags)
80 switch(STGM_ACCESS_MODE(openFlags))
82 case STGM_WRITE:
83 case STGM_READWRITE:
84 return PAGE_READWRITE;
86 return PAGE_READONLY;
89 /******************************************************************************
90 * FileLockBytesImpl_Construct
92 * Initialize a big block object supported by a file.
94 HRESULT FileLockBytesImpl_Construct(HANDLE hFile, DWORD openFlags, LPCWSTR pwcsName, ILockBytes **pLockBytes)
96 FileLockBytesImpl *This;
97 WCHAR fullpath[MAX_PATH];
99 if (hFile == INVALID_HANDLE_VALUE)
100 return E_FAIL;
102 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl));
104 if (!This)
105 return E_OUTOFMEMORY;
107 This->ILockBytes_iface.lpVtbl = &FileLockBytesImpl_Vtbl;
108 This->ref = 1;
109 This->hfile = hFile;
110 This->flProtect = GetProtectMode(openFlags);
112 if(pwcsName) {
113 if (!GetFullPathNameW(pwcsName, MAX_PATH, fullpath, NULL))
115 lstrcpynW(fullpath, pwcsName, MAX_PATH);
117 This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
118 (lstrlenW(fullpath)+1)*sizeof(WCHAR));
119 if (!This->pwcsName)
121 HeapFree(GetProcessHeap(), 0, This);
122 return E_OUTOFMEMORY;
124 strcpyW(This->pwcsName, fullpath);
126 else
127 This->pwcsName = NULL;
129 *pLockBytes = &This->ILockBytes_iface;
131 return S_OK;
134 /* ILockByte Interfaces */
136 static HRESULT WINAPI FileLockBytesImpl_QueryInterface(ILockBytes *iface, REFIID riid,
137 void **ppvObject)
139 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ILockBytes))
140 *ppvObject = iface;
141 else
143 *ppvObject = NULL;
144 return E_NOINTERFACE;
147 IUnknown_AddRef((IUnknown*)*ppvObject);
149 return S_OK;
152 static ULONG WINAPI FileLockBytesImpl_AddRef(ILockBytes *iface)
154 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
155 return InterlockedIncrement(&This->ref);
158 static ULONG WINAPI FileLockBytesImpl_Release(ILockBytes *iface)
160 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
161 ULONG ref;
163 ref = InterlockedDecrement(&This->ref);
165 if (ref == 0)
167 CloseHandle(This->hfile);
168 HeapFree(GetProcessHeap(), 0, This->pwcsName);
169 HeapFree(GetProcessHeap(), 0, This);
172 return ref;
175 /******************************************************************************
176 * This method is part of the ILockBytes interface.
178 * It reads a block of information from the byte array at the specified
179 * offset.
181 * See the documentation of ILockBytes for more info.
183 static HRESULT WINAPI FileLockBytesImpl_ReadAt(
184 ILockBytes* iface,
185 ULARGE_INTEGER ulOffset, /* [in] */
186 void* pv, /* [length_is][size_is][out] */
187 ULONG cb, /* [in] */
188 ULONG* pcbRead) /* [out] */
190 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
191 ULONG bytes_left = cb;
192 LPBYTE readPtr = pv;
193 BOOL ret;
194 LARGE_INTEGER offset;
195 ULONG cbRead;
197 TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbRead);
199 /* verify a sane environment */
200 if (!This) return E_FAIL;
202 if (pcbRead)
203 *pcbRead = 0;
205 offset.QuadPart = ulOffset.QuadPart;
207 ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
209 if (!ret)
210 return STG_E_READFAULT;
212 while (bytes_left)
214 ret = ReadFile(This->hfile, readPtr, bytes_left, &cbRead, NULL);
216 if (!ret || cbRead == 0)
217 return STG_E_READFAULT;
219 if (pcbRead)
220 *pcbRead += cbRead;
222 bytes_left -= cbRead;
223 readPtr += cbRead;
226 TRACE("finished\n");
227 return S_OK;
230 /******************************************************************************
231 * This method is part of the ILockBytes interface.
233 * It writes the specified bytes at the specified offset.
234 * position. If the file is too small, it will be resized.
236 * See the documentation of ILockBytes for more info.
238 static HRESULT WINAPI FileLockBytesImpl_WriteAt(
239 ILockBytes* iface,
240 ULARGE_INTEGER ulOffset, /* [in] */
241 const void* pv, /* [size_is][in] */
242 ULONG cb, /* [in] */
243 ULONG* pcbWritten) /* [out] */
245 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
246 ULONG bytes_left = cb;
247 const BYTE *writePtr = pv;
248 BOOL ret;
249 LARGE_INTEGER offset;
250 ULONG cbWritten;
252 TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbWritten);
254 /* verify a sane environment */
255 if (!This) return E_FAIL;
257 if (This->flProtect != PAGE_READWRITE)
258 return STG_E_ACCESSDENIED;
260 if (pcbWritten)
261 *pcbWritten = 0;
263 offset.QuadPart = ulOffset.QuadPart;
265 ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
267 if (!ret)
268 return STG_E_WRITEFAULT;
270 while (bytes_left)
272 ret = WriteFile(This->hfile, writePtr, bytes_left, &cbWritten, NULL);
274 if (!ret)
275 return STG_E_WRITEFAULT;
277 if (pcbWritten)
278 *pcbWritten += cbWritten;
280 bytes_left -= cbWritten;
281 writePtr += cbWritten;
284 TRACE("finished\n");
285 return S_OK;
288 static HRESULT WINAPI FileLockBytesImpl_Flush(ILockBytes* iface)
290 return S_OK;
293 /******************************************************************************
294 * ILockBytes_SetSize
296 * Sets the size of the file.
299 static HRESULT WINAPI FileLockBytesImpl_SetSize(ILockBytes* iface, ULARGE_INTEGER newSize)
301 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
302 HRESULT hr = S_OK;
303 LARGE_INTEGER newpos;
305 TRACE("new size %u\n", newSize.u.LowPart);
307 newpos.QuadPart = newSize.QuadPart;
308 if (SetFilePointerEx(This->hfile, newpos, NULL, FILE_BEGIN))
310 SetEndOfFile(This->hfile);
313 return hr;
316 static HRESULT get_lock_error(void)
318 switch (GetLastError())
320 case ERROR_LOCK_VIOLATION: return STG_E_LOCKVIOLATION; break;
321 case ERROR_ACCESS_DENIED: return STG_E_ACCESSDENIED; break;
322 case ERROR_NOT_SUPPORTED: return STG_E_INVALIDFUNCTION; break;
323 default:
324 FIXME("no mapping for error %d\n", GetLastError());
325 return STG_E_INVALIDFUNCTION;
329 static HRESULT WINAPI FileLockBytesImpl_LockRegion(ILockBytes* iface,
330 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
332 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
333 OVERLAPPED ol;
334 DWORD lock_flags = LOCKFILE_FAIL_IMMEDIATELY;
336 TRACE("ofs %u count %u flags %x\n", libOffset.u.LowPart, cb.u.LowPart, dwLockType);
338 if (dwLockType & LOCK_WRITE)
339 return STG_E_INVALIDFUNCTION;
341 if (dwLockType & (LOCK_EXCLUSIVE|LOCK_ONLYONCE))
342 lock_flags |= LOCKFILE_EXCLUSIVE_LOCK;
344 ol.hEvent = 0;
345 ol.u.s.Offset = libOffset.u.LowPart;
346 ol.u.s.OffsetHigh = libOffset.u.HighPart;
348 if (LockFileEx(This->hfile, lock_flags, 0, cb.u.LowPart, cb.u.HighPart, &ol))
349 return S_OK;
350 return get_lock_error();
353 HRESULT FileLockBytesImpl_LockRegionSync(ILockBytes* iface,
354 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb)
356 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
357 OVERLAPPED ol;
359 if (iface->lpVtbl != &FileLockBytesImpl_Vtbl)
360 return E_NOTIMPL;
362 ol.hEvent = 0;
363 ol.u.s.Offset = libOffset.u.LowPart;
364 ol.u.s.OffsetHigh = libOffset.u.HighPart;
366 if (LockFileEx(This->hfile, LOCKFILE_EXCLUSIVE_LOCK, 0, cb.u.LowPart, cb.u.HighPart, &ol))
367 return S_OK;
368 return get_lock_error();
371 static HRESULT WINAPI FileLockBytesImpl_UnlockRegion(ILockBytes* iface,
372 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
374 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
375 OVERLAPPED ol;
377 TRACE("ofs %u count %u flags %x\n", libOffset.u.LowPart, cb.u.LowPart, dwLockType);
379 if (dwLockType & LOCK_WRITE)
380 return STG_E_INVALIDFUNCTION;
382 ol.hEvent = 0;
383 ol.u.s.Offset = libOffset.u.LowPart;
384 ol.u.s.OffsetHigh = libOffset.u.HighPart;
386 if (UnlockFileEx(This->hfile, 0, cb.u.LowPart, cb.u.HighPart, &ol))
387 return S_OK;
388 return get_lock_error();
391 static HRESULT WINAPI FileLockBytesImpl_Stat(ILockBytes* iface,
392 STATSTG *pstatstg, DWORD grfStatFlag)
394 FileLockBytesImpl* This = impl_from_ILockBytes(iface);
396 if (!(STATFLAG_NONAME & grfStatFlag) && This->pwcsName)
398 pstatstg->pwcsName =
399 CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
401 strcpyW(pstatstg->pwcsName, This->pwcsName);
403 else
404 pstatstg->pwcsName = NULL;
406 pstatstg->type = STGTY_LOCKBYTES;
408 pstatstg->cbSize.u.LowPart = GetFileSize(This->hfile, &pstatstg->cbSize.u.HighPart);
409 /* FIXME: If the implementation is exported, we'll need to set other fields. */
411 return S_OK;
414 static const ILockBytesVtbl FileLockBytesImpl_Vtbl = {
415 FileLockBytesImpl_QueryInterface,
416 FileLockBytesImpl_AddRef,
417 FileLockBytesImpl_Release,
418 FileLockBytesImpl_ReadAt,
419 FileLockBytesImpl_WriteAt,
420 FileLockBytesImpl_Flush,
421 FileLockBytesImpl_SetSize,
422 FileLockBytesImpl_LockRegion,
423 FileLockBytesImpl_UnlockRegion,
424 FileLockBytesImpl_Stat