//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: filelkb.cxx // // Contents: File ILockBytes implementation for async storage // // Classes: // // Functions: // // History: 19-Dec-95 PhilipLa Created // //---------------------------------------------------------------------------- #include "astghead.cxx" #pragma hdrstop #include "filelkb.hxx" #include #define WIN32_SCODE(err) HRESULT_FROM_WIN32(err) #define LAST_STG_SCODE Win32ErrorToScode(GetLastError()) #define boolChk(e) \ if (!(e)) astgErr(Err, LAST_STG_SCODE) else 1 #define boolChkTo(l, e) \ if (!(e)) astgErr(l, LAST_STG_SCODE) else 1 #define negChk(e) \ if ((e) == 0xffffffff) astgErr(Err, LAST_STG_SCODE) else 1 #define negChkTo(l, e) \ if ((e) == 0xffffffff) astgErr(l, LAST_STG_SCODE) else 1 class CSafeCriticalSection { public: inline CSafeCriticalSection(CRITICAL_SECTION *pcs); inline ~CSafeCriticalSection(); private: CRITICAL_SECTION *_pcs; }; inline CSafeCriticalSection::CSafeCriticalSection(CRITICAL_SECTION *pcs) { _pcs = pcs; EnterCriticalSection(_pcs); } inline CSafeCriticalSection::~CSafeCriticalSection() { LeaveCriticalSection(_pcs); #if DBG == 1 _pcs = NULL; #endif } #define TAKE_CS CSafeCriticalSection scs(&_cs); //+--------------------------------------------------------------------------- // // Function: Win32ErrorToScode, public // // Synopsis: Map a Win32 error into a corresponding scode, remapping // into Facility_Storage if appropriate. // // Arguments: [dwErr] -- Win32 error to map // // Returns: Appropriate scode // // History: 22-Sep-93 PhilipLa Created // //---------------------------------------------------------------------------- SCODE Win32ErrorToScode(DWORD dwErr) { astgAssert((dwErr != NO_ERROR) && "Win32ErrorToScode called on NO_ERROR"); SCODE sc = STG_E_UNKNOWN; switch (dwErr) { case ERROR_INVALID_FUNCTION: sc = STG_E_INVALIDFUNCTION; break; case ERROR_FILE_NOT_FOUND: sc = STG_E_FILENOTFOUND; break; case ERROR_PATH_NOT_FOUND: sc = STG_E_PATHNOTFOUND; break; case ERROR_TOO_MANY_OPEN_FILES: sc = STG_E_TOOMANYOPENFILES; break; case ERROR_ACCESS_DENIED: case ERROR_NETWORK_ACCESS_DENIED: sc = STG_E_ACCESSDENIED; break; case ERROR_INVALID_HANDLE: sc = STG_E_INVALIDHANDLE; break; case ERROR_NOT_ENOUGH_MEMORY: sc = STG_E_INSUFFICIENTMEMORY; break; case ERROR_NO_MORE_FILES: sc = STG_E_NOMOREFILES; break; case ERROR_WRITE_PROTECT: sc = STG_E_DISKISWRITEPROTECTED; break; case ERROR_SEEK: sc = STG_E_SEEKERROR; break; case ERROR_WRITE_FAULT: sc = STG_E_WRITEFAULT; break; case ERROR_READ_FAULT: sc = STG_E_READFAULT; break; case ERROR_SHARING_VIOLATION: sc = STG_E_SHAREVIOLATION; break; case ERROR_LOCK_VIOLATION: sc = STG_E_LOCKVIOLATION; break; case ERROR_HANDLE_DISK_FULL: case ERROR_DISK_FULL: sc = STG_E_MEDIUMFULL; break; case ERROR_FILE_EXISTS: case ERROR_ALREADY_EXISTS: sc = STG_E_FILEALREADYEXISTS; break; case ERROR_INVALID_PARAMETER: sc = STG_E_INVALIDPARAMETER; break; case ERROR_INVALID_NAME: case ERROR_BAD_PATHNAME: case ERROR_FILENAME_EXCED_RANGE: sc = STG_E_INVALIDNAME; break; case ERROR_INVALID_FLAGS: sc = STG_E_INVALIDFLAG; break; default: sc = WIN32_SCODE(dwErr); break; } return sc; } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::CFileLockBytes, public // // Synopsis: Default constructor // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- CFileLockBytes::CFileLockBytes(void) { _cReferences = 1; _h = INVALID_HANDLE_VALUE; InitializeCriticalSection(&_cs); } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::~CFileLockBytes, public // // Synopsis: Destructor // // Returns: Appropriate status code // // History: 28-Dec-95 PhilipLa Created // //---------------------------------------------------------------------------- CFileLockBytes::~CFileLockBytes() { if (_h != INVALID_HANDLE_VALUE) { CloseHandle(_h); } DeleteCriticalSection(&_cs); } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::Init, public // // Synopsis: Initialization function // // Arguments: // // Returns: Appropriate status code // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- SCODE CFileLockBytes::Init(OLECHAR const *pwcsName) { astgDebugOut((DEB_ITRACE, "In CFileLockBytes::Init:%p()\n", this)); #ifndef UNICODE TCHAR atcPath[_MAX_PATH + 1]; UINT uCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; if (!WideCharToMultiByte( uCodePage, 0, pwcsName, -1, atcPath, _MAX_PATH + 1, NULL, NULL)) { return STG_E_INVALIDNAME; } _h = CreateFileA(atcPath, GENERIC_READ | GENERIC_WRITE, //Read-write 0, // No sharing NULL, CREATE_NEW, //Create if necessary FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); #else _h = CreateFile(pwcsName, GENERIC_READ | GENERIC_WRITE, //Read-write 0, // No sharing NULL, CREATE_NEW, //Create if necessary FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); #endif if (_h == INVALID_HANDLE_VALUE) { return LAST_STG_SCODE; } wcscpy(_acName, pwcsName); astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::Init\n")); return S_OK; } //+-------------------------------------------------------------- // // Member: CFileLockBytes::QueryInterface, public // // Synopsis: Returns an object for the requested interface // // Arguments: [iid] - Interface ID // [ppvObj] - Object return // // Returns: Appropriate status code // // Modifies: [ppvObj] // // History: 26-Mar-92 DrewB Created // //--------------------------------------------------------------- STDMETHODIMP CFileLockBytes::QueryInterface(REFIID iid, void **ppvObj) { TAKE_CS; SCODE sc; astgDebugOut((DEB_ITRACE, "In CFileLockBytes::QueryInterface(?, %p)\n", ppvObj)); astgChk(ValidateOutPtrBuffer(ppvObj)); *ppvObj = NULL; sc = S_OK; if (IsEqualIID(iid, IID_IUnknown)) { *ppvObj = (IUnknown *)this; CFileLockBytes::AddRef(); } else if (IsEqualIID(iid, IID_ILockBytes)) { *ppvObj = (ILockBytes *)this; CFileLockBytes::AddRef(); } else { sc = E_NOINTERFACE; } astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::QueryInterface => %p\n", ppvObj)); Err: return ResultFromScode(sc); } //+-------------------------------------------------------------- // // Member: CFileLockBytes::AddRef, public // // Synopsis: Increments the ref count // // Returns: Appropriate status code // // History: 16-Mar-92 DrewB Created // //--------------------------------------------------------------- STDMETHODIMP_(ULONG) CFileLockBytes::AddRef(void) { ULONG ulRet; astgDebugOut((DEB_TRACE, "In CFileLockBytes::AddRef()\n")); InterlockedIncrement(&_cReferences); ulRet = _cReferences; astgDebugOut((DEB_TRACE, "Out CFileLockBytes::AddRef\n")); return ulRet; } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::Release, public // // History: 28-Dec-95 PhilipLa Created // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CFileLockBytes::Release(void) { LONG lRet; astgDebugOut((DEB_ITRACE, "In CFileLockBytes::Release:%p()\n", this)); lRet = InterlockedDecrement(&_cReferences); if (lRet == 0) { delete this; } else if (lRet < 0) { lRet = 0; } astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::Release\n")); return lRet; } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::ReadAt, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CFileLockBytes::ReadAt(ULARGE_INTEGER ulOffset, VOID HUGEP *pv, ULONG cb, ULONG *pcbRead) { TAKE_CS; SCODE sc = S_OK; astgDebugOut((DEB_ITRACE, "In CFileLockBytes::ReadAt:%p()\n", this)); ULONG ulLow = ulOffset.LowPart; LONG lHigh = (LONG)ulOffset.HighPart; negChk(SetFilePointer(_h, ulLow, &lHigh, FILE_BEGIN)); boolChk(ReadFile(_h, pv, cb, pcbRead, NULL)); astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::ReadAt\n")); Err: return sc; } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::WriteAt, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CFileLockBytes::WriteAt(ULARGE_INTEGER ulOffset, VOID const HUGEP *pv, ULONG cb, ULONG *pcbWritten) { TAKE_CS; SCODE sc = S_OK; astgDebugOut((DEB_ITRACE, "In CFileLockBytes::WriteAt:%p()\n", this)); ULONG ulLow = ulOffset.LowPart; LONG lHigh = (LONG)ulOffset.HighPart; negChk(SetFilePointer(_h, ulLow, &lHigh, FILE_BEGIN)); boolChk(WriteFile(_h, pv, cb, pcbWritten, NULL)); astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::WriteAt\n")); Err: return sc; } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::Flush, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- //BUGBUG: Implement something here? STDMETHODIMP CFileLockBytes::Flush(void) { TAKE_CS; astgDebugOut((DEB_ITRACE, "In CFileLockBytes::Flush:%p()\n", this)); astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::Flush\n")); return S_OK; } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::SetSize, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CFileLockBytes::SetSize(ULARGE_INTEGER cb) { TAKE_CS; SCODE sc = S_OK; astgDebugOut((DEB_ITRACE, "In CFileLockBytes::SetSize:%p()\n", this)); LONG lHigh = (LONG)cb.HighPart; ULONG ulLow = cb.LowPart; negChk(SetFilePointer(_h, ulLow, &lHigh, FILE_BEGIN)); boolChk(SetEndOfFile(_h)); astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::SetSize\n")); Err: return sc; } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::LockRegion, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CFileLockBytes::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { TAKE_CS; SCODE sc = S_OK; astgDebugOut((DEB_ITRACE, "In CFileLockBytes::LockRegion:%p()\n", this)); if (dwLockType != LOCK_EXCLUSIVE && dwLockType != LOCK_ONLYONCE) { return STG_E_INVALIDFUNCTION; } boolChk(LockFile(_h, libOffset.LowPart, libOffset.HighPart, cb.LowPart, cb.HighPart)); astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::LockRegion\n")); Err: return sc; } //+--------------------------------------------------------------------------- // // Member: CFileLockBytes::UnlockRegion, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CFileLockBytes::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { TAKE_CS; SCODE sc = S_OK; astgDebugOut((DEB_ITRACE, "In CFileLockBytes::UnlockRegion:%p()\n", this)); if (dwLockType != LOCK_EXCLUSIVE && dwLockType != LOCK_ONLYONCE) { return STG_E_INVALIDFUNCTION; } boolChk(UnlockFile(_h, libOffset.LowPart, libOffset.HighPart, cb.LowPart, cb.HighPart)); astgDebugOut((DEB_ITRACE, "Out CFileLockBytes::UnlockRegion\n")); Err: return sc; } //+--------------------------------------------------------------------------- // // Member: CFIleLockBytes::Stat, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 28-Dec-95 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CFileLockBytes::Stat(STATSTG *pstatstg, DWORD grfStatFlag) { TAKE_CS; SCODE sc; astgDebugOut((DEB_ITRACE, "In CFIleLockBytes::Stat:%p()\n", this)); negChk(pstatstg->cbSize.LowPart = GetFileSize(_h, &pstatstg->cbSize.HighPart)); boolChk(GetFileTime(_h, &pstatstg->ctime, &pstatstg->atime, &pstatstg->mtime)); pstatstg->grfLocksSupported = LOCK_EXCLUSIVE | LOCK_ONLYONCE; pstatstg->type = STGTY_LOCKBYTES; //BUGBUG: Set grfMode //pstatstg->grfMode = DFlagsToMode(_pgfst->GetDFlags()); pstatstg->pwcsName = NULL; if ((grfStatFlag & STATFLAG_NONAME) == 0) { pstatstg->pwcsName = (OLECHAR *)CoTaskMemAlloc( (wcslen(_acName) + 1) * sizeof(OLECHAR)); if (pstatstg->pwcsName == NULL) return STG_E_INSUFFICIENTMEMORY; wcscpy(pstatstg->pwcsName, _acName); } sc = S_OK; astgDebugOut((DEB_ITRACE, "Out CFIleLockBytes::Stat\n")); return NOERROR; Err: return sc; }