diff options
Diffstat (limited to 'store')
41 files changed, 16162 insertions, 0 deletions
diff --git a/store/inc/makefile.mk b/store/inc/makefile.mk new file mode 100644 index 000000000000..7702b58970b8 --- /dev/null +++ b/store/inc/makefile.mk @@ -0,0 +1,51 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.3 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=.. + +PRJNAME=store +TARGET=inc + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk + +.IF "$(ENABLE_PCH)"!="" +ALLTAR : \ + $(SLO)$/precompiled.pch \ + $(SLO)$/precompiled_ex.pch + +.ENDIF # "$(ENABLE_PCH)"!="" + diff --git a/store/inc/pch/precompiled_store.cxx b/store/inc/pch/precompiled_store.cxx new file mode 100644 index 000000000000..4a539b879e27 --- /dev/null +++ b/store/inc/pch/precompiled_store.cxx @@ -0,0 +1,32 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: precompiled_store.cxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_store.hxx" + diff --git a/store/inc/pch/precompiled_store.hxx b/store/inc/pch/precompiled_store.hxx new file mode 100644 index 000000000000..85b750d40589 --- /dev/null +++ b/store/inc/pch/precompiled_store.hxx @@ -0,0 +1,35 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: precompiled_store.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): Generated on 2006-09-01 17:50:03.342334 + +#ifdef PRECOMPILED_HEADERS +#endif + diff --git a/store/inc/store/store.h b/store/inc/store/store.h new file mode 100644 index 000000000000..3a46f272daf4 --- /dev/null +++ b/store/inc/store/store.h @@ -0,0 +1,414 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: store.h,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORE_H_ +#define _STORE_STORE_H_ "$Revision: 1.6 $" + +#include <store/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** Handle opaque type. + */ +typedef void* storeHandle; + + +/** Acquire a Handle. + @param Handle [in] the Handle. + @return store_E_None upon success + */ +storeError SAL_CALL store_acquireHandle ( + storeHandle Handle +) SAL_THROW_EXTERN_C(); + + +/** Release a Handle. + @param Handle [in] the Handle. + @return store_E_None upon success, + store_E_InvalidHandle otherwise. + */ +storeError SAL_CALL store_releaseHandle ( + storeHandle Handle +) SAL_THROW_EXTERN_C(); + + + +/** File Handle opaque type. + */ +typedef void* storeFileHandle; + + +/** Open a temporary file in memory. + @param nPageSize [in] the creation page size, + integer multiple of minimum page size. + @param phFile [out] the File Handle. + @return store_E_None upon success + */ +storeError SAL_CALL store_createMemoryFile ( + sal_uInt16 nPageSize, + storeFileHandle *phFile +) SAL_THROW_EXTERN_C(); + + +/** Open a file. + @param pFilename [in] the filename as URL or system path. + @param eAccessMode [in] the access mode. + store_AccessCreate truncate existing and create, + store_AccessReadCreate create not existing, + store_AccessReadWrite write existing, + store_AccessReadOnly never modifies. + @param nPageSize [in] the creation page size, + integer multiple of minimum page size. + @param phFile [out] the File Handle. + @return store_E_None upon success + */ +storeError SAL_CALL store_openFile ( + rtl_uString *pFilename, + storeAccessMode eAccessMode, + sal_uInt16 nPageSize, + storeFileHandle *phFile +) SAL_THROW_EXTERN_C(); + + +/** Close a file. + @param hFile [in] the File Handle. + @return store_E_None upon success, + store_E_InvalidHandle otherwise. + */ +storeError SAL_CALL store_closeFile ( + storeFileHandle hFile +) SAL_THROW_EXTERN_C(); + + +/** Flush a file. + @param hFile [in] the File Handle. + @return store_E_None upon success + */ +storeError SAL_CALL store_flushFile ( + storeFileHandle hFile +) SAL_THROW_EXTERN_C(); + + +/** Get the number of referers to a file. + @param hFile [in] the File Handle. + @param pnRefCount [out] number of open directories and streams. + @return store_E_None upon success + */ +storeError SAL_CALL store_getFileRefererCount ( + storeFileHandle hFile, + sal_uInt32 *pnRefCount +) SAL_THROW_EXTERN_C(); + + +/** Get the size of a file. + @param hFile [in] the File Handle. + @param pnSize [out] the file size in bytes. + @return store_E_None upon success + */ +storeError SAL_CALL store_getFileSize ( + storeFileHandle hFile, + sal_uInt32 *pnSize +) SAL_THROW_EXTERN_C(); + + +/** Recover and Compact a file into another file. + @see store_openFile() + + @param pSrcFilename [in] opened with store_AccessReadOnly. + @param pDstFilename [in] created with store_AccessCreate. + @return store_E_None upon success + */ +storeError SAL_CALL store_rebuildFile ( + rtl_uString *pSrcFilename, + rtl_uString *pDstFilename +) SAL_THROW_EXTERN_C(); + + + +/** Directory Handle opaque type. + */ +typedef void* storeDirectoryHandle; + + +/** Open a directory. + @see store_openFile() + + @param hFile [in] the File Handle. + @param pPath [in] the directory path. + @param pName [in] the directory name. + @param eAccessMode [in] the access mode. + @param phDirectory [out] the Directory Handle. + @return store_E_None upon success + */ +storeError SAL_CALL store_openDirectory ( + storeFileHandle hFile, + rtl_uString *pPath, + rtl_uString *pName, + storeAccessMode eAccessMode, + storeDirectoryHandle *phDirectory +) SAL_THROW_EXTERN_C(); + + +/** Close a directory. + @param hDirectory [in] the Directory Handle. + @return store_E_None upon success, + store_E_InvalidHandle otherwise. + */ +storeError SAL_CALL store_closeDirectory ( + storeDirectoryHandle hDirectory +) SAL_THROW_EXTERN_C(); + + +/** Find first directory entry. + @param hDirectory [in] the Directory Handle. + @param pFindData [out] the Find Data structure. + @return store_E_None upon success, + store_E_NoMoreFile upon end of iteration. + */ +storeError SAL_CALL store_findFirst ( + storeDirectoryHandle hDirectory, + storeFindData *pFindData +) SAL_THROW_EXTERN_C(); + + +/** Find next directory entry. + @param hDirectory [in] the Directory Handle. + @param pFindData [out] the Find Data structure. + @return store_E_None upon success, + store_E_NoMoreFile upon end of iteration. + */ +storeError SAL_CALL store_findNext ( + storeDirectoryHandle hDirectory, + storeFindData *pFindData +) SAL_THROW_EXTERN_C(); + + + +/** Stream Handle opaque type. + */ +typedef void* storeStreamHandle; + + +/** Open a stream. + @see store_openFile() + + @param hFile [in] the File Handle. + @param pPath [in] the stream path. + @param pName [in] the stream name. + @param eAccessMode [in] the access mode. + @param phStrm [out] the Stream Handle. + @return store_E_None upon success + */ +storeError SAL_CALL store_openStream ( + storeFileHandle hFile, + rtl_uString *pPath, + rtl_uString *pName, + storeAccessMode eMode, + storeStreamHandle *phStrm +) SAL_THROW_EXTERN_C(); + + +/** Close a stream. + @param hStrm [in] the Stream Handle. + @return store_E_None upon success, + store_E_InvalidHandle otherwise. + */ +storeError SAL_CALL store_closeStream ( + storeStreamHandle hStrm +) SAL_THROW_EXTERN_C(); + + +/** Read from a stream. + @param hStrm [in] the Stream Handle. + @param nOffset [in] the offset of the first byte to read. + @param pBuffer [out] the buffer. + @param nBytes [in] the number of bytes to read. + @param pnDone [out] the number of bytes actually read. + @return store_E_None upon success + */ +storeError SAL_CALL store_readStream ( + storeStreamHandle hStrm, + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 *pnDone +) SAL_THROW_EXTERN_C(); + + +/** Write to a stream. + @param hStrm [in] the Stream Handle. + @param nOffset [in] the offset of the first byte to write. + @param pBuffer [in] the buffer. + @param nBytes [in] the number of bytes to write. + @param pnDone [out] the number of bytes actually written. + @return store_E_None upon success + */ +storeError SAL_CALL store_writeStream ( + storeStreamHandle hStrm, + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 *pnDone +) SAL_THROW_EXTERN_C(); + + +/** Flush a stream. + @param hStrm [in] the Stream Handle. + @return store_E_None upon success + */ +storeError SAL_CALL store_flushStream ( + storeStreamHandle hStrm +) SAL_THROW_EXTERN_C(); + + +/** Get the size of a stream. + @param hStrm [in] the Stream Handle. + @param pnSize [out] the stream size in bytes. + @return store_E_None upon success + */ +storeError SAL_CALL store_getStreamSize ( + storeStreamHandle hStrm, + sal_uInt32 *pnSize +) SAL_THROW_EXTERN_C(); + + +/** Set the size of a stream. + @param hStrm [in] the Stream Handle. + @param nSize [in] the new stream size in bytes. + @return store_E_None upon success + */ +storeError SAL_CALL store_setStreamSize ( + storeStreamHandle hStrm, + sal_uInt32 nSize +) SAL_THROW_EXTERN_C(); + + + +/** Set attributes of a file entry. + @param hFile [in] the File Handle. + @param pPath [in] the entry path. + @param pName [in] the entry name. + @param nMask1 [in] the attributes to be cleared. + @param nMask2 [in] the attributes to be set. + @param pnAttrib [out] the resulting attributes, may be NULL. + @return store_E_None upon success + */ +storeError SAL_CALL store_attrib ( + storeFileHandle hFile, + rtl_uString *pPath, + rtl_uString *pName, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 *pnAttrib +) SAL_THROW_EXTERN_C(); + + +/** Insert a file entry as 'hard link' to another file entry. + @precond Source must not exist, Destination must exist. + @postcond Source has attribute STORE_ATTRIB_ISLINK. + @see store_attrib() + + @param hFile [in] the File Handle + @param pSrcPath [in] the Source path + @param pSrcName [in] the Source name + @param pDstPath [in] the Destination path + @param pDstName [in] the Destination name + @return store_E_None upon success + */ +storeError SAL_CALL store_link ( + storeFileHandle hFile, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C(); + + +/** Insert a file entry as 'symbolic link' to another file entry. + @precond Source must not exist + @postcond Source has attribute STORE_ATTRIB_ISLINK. + @see store_attrib() + + @param hFile [in] the File Handle + @param pSrcPath [in] the Source path + @param pSrcName [in] the Source name + @param pDstPath [in] the Destination path + @param pDstName [in] the Destination name + @return store_E_None upon success + */ +storeError SAL_CALL store_symlink ( + storeFileHandle hFile, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C(); + + +/** Rename a file entry. + @param hFile [in] the File Handle + @param pSrcPath [in] the Source path + @param pSrcName [in] the Source name + @param pDstPath [in] the Destination path + @param pDstName [in] the Destination name + @return store_E_None upon success + */ +storeError SAL_CALL store_rename ( + storeFileHandle hFile, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C(); + + +/** Remove a file entry. + @param hFile [in] the File Handle + @param pPath [in] the entry path + @param pName [in] the entry name + @return store_E_None upon success + */ +storeError SAL_CALL store_remove ( + storeFileHandle hFile, + rtl_uString *pPath, + rtl_uString *pName +) SAL_THROW_EXTERN_C(); + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _STORE_STORE_H_ */ + + + + diff --git a/store/inc/store/store.hxx b/store/inc/store/store.hxx new file mode 100644 index 000000000000..54f0d44024b8 --- /dev/null +++ b/store/inc/store/store.hxx @@ -0,0 +1,390 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: store.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORE_HXX_ +#define _STORE_STORE_HXX_ "$Revision: 1.5 $" + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <store/store.h> + +namespace store +{ + +/*======================================================================== + * + * OStoreStream interface. + * + *======================================================================*/ +class OStoreStream +{ +public: + /** Construction. + */ + inline OStoreStream (void) SAL_THROW(()); + + /** Destruction. + */ + inline ~OStoreStream (void) SAL_THROW(()); + + /** Copy construction. + */ + inline OStoreStream ( + const OStoreStream& rOther) SAL_THROW(()); + + /** Assignment. + */ + inline OStoreStream& operator= ( + const OStoreStream& rOther) SAL_THROW(()); + + + /** Construction from Stream Handle. + */ + inline OStoreStream (storeStreamHandle Handle) SAL_THROW(()); + + /** Conversion into Stream Handle. + */ + inline operator storeStreamHandle (void) const SAL_THROW(()); + + /** Check for a valid Stream Handle. + @return sal_True if valid, sal_False otherwise. + */ + inline sal_Bool isValid (void) const SAL_THROW(()); + + + /** Open the stream. + @see store_openStream() + */ + inline storeError create ( + storeFileHandle hFile, + const rtl::OUString &rPath, + const rtl::OUString &rName, + storeAccessMode eMode + ) SAL_THROW(()); + + /** Close the stream. + @see store_closeStream() + */ + inline void close (void) SAL_THROW(()); + + /** Read from the stream. + @see store_readStream() + */ + inline storeError readAt ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone + ) SAL_THROW(()); + + /** Write to the stream. + @see store_writeStream() + */ + inline storeError writeAt ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone + ) SAL_THROW(()); + + /** Flush the stream. + @see store_flushStream() + */ + inline storeError flush (void) const SAL_THROW(()); + + /** Get the stream size. + @see store_getStreamSize() + */ + inline storeError getSize (sal_uInt32 &rnSize) const SAL_THROW(()); + + /** Set the stream size. + @see store_setStreamSize() + */ + inline storeError setSize (sal_uInt32 nSize) SAL_THROW(()); + +private: + /** Representation. + */ + storeStreamHandle m_hImpl; +}; + +/*======================================================================== + * + * OStoreDirectory interface. + * + *======================================================================*/ +class OStoreDirectory +{ +public: + /** Construction. + */ + inline OStoreDirectory (void) SAL_THROW(()); + + /** Destruction. + */ + inline ~OStoreDirectory (void) SAL_THROW(()); + + /** Copy construction. + */ + inline OStoreDirectory ( + const OStoreDirectory& rOther) SAL_THROW(()); + + /** Assignment. + */ + inline OStoreDirectory& operator= ( + const OStoreDirectory& rOther) SAL_THROW(()); + + + /** Construction from Directory Handle. + */ + inline OStoreDirectory (storeDirectoryHandle Handle) SAL_THROW(()); + + /** Conversion into Directory Handle. + */ + inline operator storeDirectoryHandle (void) const SAL_THROW(()); + + /** Check for a valid Directory Handle. + @return sal_True if valid, sal_False otherwise. + */ + inline sal_Bool isValid (void) const SAL_THROW(()); + + + /** Open the directory. + @see store_openDirectory() + */ + inline storeError create ( + storeFileHandle hFile, + const rtl::OUString &rPath, + const rtl::OUString &rName, + storeAccessMode eMode + ) SAL_THROW(()); + + /** Close the directory. + @see store_closeDirectory() + */ + inline void close (void) SAL_THROW(()); + + + /** Directory iterator type. + @see first() + @see next() + */ + typedef storeFindData iterator; + + /** Find first directory entry. + @see store_findFirst() + */ + inline storeError first (iterator& it) SAL_THROW(()); + + /** Find next directory entry. + @see store_findNext() + */ + inline storeError next (iterator& it) SAL_THROW(()); + + /** Directory traversal helper. + @see travel() + */ + class traveller + { + public: + /** Directory traversal callback. + @param it [in] current directory entry. + @return sal_True to continue iteration, sal_False to stop. + */ + virtual sal_Bool visit (const iterator& it) = 0; + }; + + /** Directory traversal. + @see store_findFirst() + @see store_findNext() + + @param rTraveller [in] the traversal callback. + @return store_E_NoMoreFiles upon end of iteration. + */ + inline storeError travel (traveller& rTraveller) const; + +private: + /** Representation. + */ + storeDirectoryHandle m_hImpl; +}; + +/*======================================================================== + * + * OStoreFile interface. + * + *======================================================================*/ +class OStoreFile +{ +public: + /** Construction. + */ + inline OStoreFile (void) SAL_THROW(()); + + /** Destruction. + */ + inline ~OStoreFile (void) SAL_THROW(()); + + /** Copy construction. + */ + inline OStoreFile (const OStoreFile& rOther) SAL_THROW(()); + + /** Assignment. + */ + inline OStoreFile& operator= (const OStoreFile& rOther) SAL_THROW(()); + + + /** Construction from File Handle. + */ + inline OStoreFile (storeFileHandle Handle) SAL_THROW(()); + + /** Conversion into File Handle. + */ + inline operator storeFileHandle (void) const SAL_THROW(()); + + /** Check for a valid File Handle. + @return sal_True if valid, sal_False otherwise. + */ + inline sal_Bool isValid (void) const SAL_THROW(()); + + + /** Open the file. + @see store_openFile() + */ + inline storeError create ( + const rtl::OUString &rFilename, + storeAccessMode eAccessMode, + sal_uInt16 nPageSize = STORE_DEFAULT_PAGESIZE + ) SAL_THROW(()); + + /** Open the temporary file in memory. + @see store_createMemoryFile() + */ + inline storeError createInMemory ( + sal_uInt16 nPageSize = STORE_DEFAULT_PAGESIZE + ) SAL_THROW(()); + + /** Close the file. + @see store_closeFile() + */ + inline void close (void) SAL_THROW(()); + + /** Flush the file. + @see store_flushFile() + */ + inline storeError flush (void) const SAL_THROW(()); + + /** Get the number of referers to the file. + @see store_getFileRefererCount() + */ + inline storeError getRefererCount ( + sal_uInt32 &rnRefCount) const SAL_THROW(()); + + /** Get the file size. + @see store_getFileSize() + */ + inline storeError getSize ( + sal_uInt32 &rnSize) const SAL_THROW(()); + + + /** Set attributes of a file entry. + @see store_attrib() + */ + inline storeError attrib ( + const rtl::OUString &rPath, + const rtl::OUString &rName, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 &rnAttrib + ) SAL_THROW(()); + + /** Set attributes of a file entry. + @see store_attrib() + */ + inline storeError attrib ( + const rtl::OUString &rPath, + const rtl::OUString &rName, + sal_uInt32 nMask1, + sal_uInt32 nMask2 + ) SAL_THROW(()); + + /** Insert a file entry as 'hard link' to another file entry. + @see store_link() + */ + inline storeError link ( + const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName, + const rtl::OUString &rDstPath, const rtl::OUString &rDstName + ) SAL_THROW(()); + + /** Insert a file entry as 'symbolic link' to another file entry. + @see store_symlink() + */ + inline storeError symlink ( + const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName, + const rtl::OUString &rDstPath, const rtl::OUString &rDstName + ) SAL_THROW(()); + + /** Rename a file entry. + @see store_rename() + */ + inline storeError rename ( + const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName, + const rtl::OUString &rDstPath, const rtl::OUString &rDstName + ) SAL_THROW(()); + + /** Remove a file entry. + @see store_remove() + */ + inline storeError remove ( + const rtl::OUString &rPath, + const rtl::OUString &rName + ) SAL_THROW(()); + +private: + /** Representation. + */ + storeFileHandle m_hImpl; +}; + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +#include <store/store.inl> + +} // namespace store + +#endif /* !_STORE_STORE_HXX_ */ + + + + diff --git a/store/inc/store/store.inl b/store/inc/store/store.inl new file mode 100644 index 000000000000..35aff6dde1e2 --- /dev/null +++ b/store/inc/store/store.inl @@ -0,0 +1,454 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: store.inl,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define _STORE_STORE_INL_ "$Revision: 1.4 $" + +/*======================================================================== + * + * OStoreStream implementation. + * + *======================================================================*/ +inline OStoreStream::OStoreStream (void) SAL_THROW(()) + : m_hImpl (0) +{ +} + +inline OStoreStream::~OStoreStream (void) SAL_THROW(()) +{ + if (m_hImpl) + store_releaseHandle (m_hImpl); +} + +inline OStoreStream::OStoreStream ( + const OStoreStream& rOther) SAL_THROW(()) + : m_hImpl (rOther.m_hImpl) +{ + if (m_hImpl) + store_acquireHandle (m_hImpl); +} + +inline OStoreStream& OStoreStream::operator= ( + const OStoreStream& rOther) SAL_THROW(()) +{ + if (m_hImpl) + store_releaseHandle (m_hImpl); + m_hImpl = rOther.m_hImpl; + if (m_hImpl) + store_acquireHandle (m_hImpl); + return *this; +} + +inline OStoreStream::OStoreStream ( + storeStreamHandle Handle) SAL_THROW(()) + : m_hImpl (Handle) +{ + if (m_hImpl) + store_acquireHandle (m_hImpl); +} + +inline OStoreStream::operator storeStreamHandle (void) const SAL_THROW(()) +{ + return m_hImpl; +} + +inline sal_Bool OStoreStream::isValid (void) const SAL_THROW(()) +{ + return (!!m_hImpl); +} + +inline storeError OStoreStream::create ( + storeFileHandle hFile, + const rtl::OUString &rPath, + const rtl::OUString &rName, + storeAccessMode eMode) SAL_THROW(()) +{ + if (m_hImpl) + { + store_releaseHandle (m_hImpl); + m_hImpl = 0; + } + return store_openStream ( + hFile, rPath.pData, rName.pData, eMode, &m_hImpl); +} + +inline void OStoreStream::close (void) SAL_THROW(()) +{ + if (m_hImpl) + { + store_closeStream (m_hImpl); + m_hImpl = 0; + } +} + +inline storeError OStoreStream::readAt ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_readStream ( + m_hImpl, nOffset, pBuffer, nBytes, &rnDone); +} + +inline storeError OStoreStream::writeAt ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_writeStream ( + m_hImpl, nOffset, pBuffer, nBytes, &rnDone); +} + +inline storeError OStoreStream::flush (void) const SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_flushStream (m_hImpl); +} + +inline storeError OStoreStream::getSize ( + sal_uInt32 &rnSize) const SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_getStreamSize (m_hImpl, &rnSize); +} + +inline storeError OStoreStream::setSize ( + sal_uInt32 nSize) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_setStreamSize (m_hImpl, nSize); +} + +/*======================================================================== + * + * OStoreDirectory implementation. + * + *======================================================================*/ +inline OStoreDirectory::OStoreDirectory (void) SAL_THROW(()) + : m_hImpl (0) +{ +} + +inline OStoreDirectory::~OStoreDirectory (void) SAL_THROW(()) +{ + if (m_hImpl) + store_releaseHandle (m_hImpl); +} + +inline OStoreDirectory::OStoreDirectory ( + const OStoreDirectory& rOther) SAL_THROW(()) + : m_hImpl (rOther.m_hImpl) +{ + if (m_hImpl) + store_acquireHandle (m_hImpl); +} + +inline OStoreDirectory& OStoreDirectory::operator= ( + const OStoreDirectory& rOther) SAL_THROW(()) +{ + if (m_hImpl) + store_releaseHandle (m_hImpl); + m_hImpl = rOther.m_hImpl; + if (m_hImpl) + store_acquireHandle (m_hImpl); + return *this; +} + +inline OStoreDirectory::OStoreDirectory ( + storeDirectoryHandle Handle) SAL_THROW(()) + : m_hImpl (Handle) +{ + if (m_hImpl) + store_acquireHandle (m_hImpl); +} + +inline OStoreDirectory::operator storeDirectoryHandle(void) const SAL_THROW(()) +{ + return m_hImpl; +} + +inline sal_Bool OStoreDirectory::isValid (void) const SAL_THROW(()) +{ + return (!!m_hImpl); +} + +inline storeError OStoreDirectory::create ( + storeFileHandle hFile, + const rtl::OUString &rPath, + const rtl::OUString &rName, + storeAccessMode eMode) SAL_THROW(()) +{ + if (m_hImpl) + { + store_releaseHandle (m_hImpl); + m_hImpl = 0; + } + return store_openDirectory ( + hFile, rPath.pData, rName.pData, eMode, &m_hImpl); +} + +inline void OStoreDirectory::close (void) SAL_THROW(()) +{ + if (m_hImpl) + { + store_closeDirectory (m_hImpl); + m_hImpl = 0; + } +} + +inline storeError OStoreDirectory::first (iterator& it) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_findFirst (m_hImpl, &it); +} + +inline storeError OStoreDirectory::next (iterator& it) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_findNext (m_hImpl, &it); +} + +inline storeError OStoreDirectory::travel (traveller& rTraveller) const +{ + storeError eErrCode = store_E_InvalidHandle; + if (m_hImpl) + { + iterator it; + eErrCode = store_findFirst (m_hImpl, &it); + while ((eErrCode == store_E_None) && rTraveller.visit(it)) + eErrCode = store_findNext (m_hImpl, &it); + } + return eErrCode; +} + +/*======================================================================== + * + * OStoreFile implementation. + * + *======================================================================*/ +inline OStoreFile::OStoreFile (void) SAL_THROW(()) + : m_hImpl (0) +{ +} + +inline OStoreFile::~OStoreFile (void) SAL_THROW(()) +{ + if (m_hImpl) + store_releaseHandle (m_hImpl); +} + +inline OStoreFile::OStoreFile ( + const OStoreFile& rOther) SAL_THROW(()) + : m_hImpl (rOther.m_hImpl) +{ + if (m_hImpl) + store_acquireHandle (m_hImpl); +} + +inline OStoreFile& OStoreFile::operator= ( + const OStoreFile& rOther) SAL_THROW(()) +{ + if (m_hImpl) + store_releaseHandle (m_hImpl); + m_hImpl = rOther.m_hImpl; + if (m_hImpl) + store_acquireHandle (m_hImpl); + return *this; +} + +inline OStoreFile::OStoreFile ( + storeFileHandle Handle) SAL_THROW(()) + : m_hImpl (Handle) +{ + if (m_hImpl) + store_acquireHandle (m_hImpl); +} + +inline OStoreFile::operator storeFileHandle (void) const SAL_THROW(()) +{ + return m_hImpl; +} + +inline sal_Bool OStoreFile::isValid (void) const SAL_THROW(()) +{ + return (!!m_hImpl); +} + +inline storeError OStoreFile::create ( + const rtl::OUString &rFilename, + storeAccessMode eAccessMode, + sal_uInt16 nPageSize) SAL_THROW(()) +{ + if (m_hImpl) + { + store_releaseHandle (m_hImpl); + m_hImpl = 0; + } + return store_openFile (rFilename.pData, eAccessMode, nPageSize, &m_hImpl); +} + +inline storeError OStoreFile::createInMemory ( + sal_uInt16 nPageSize) SAL_THROW(()) +{ + if (m_hImpl) + { + store_releaseHandle (m_hImpl); + m_hImpl = 0; + } + return store_createMemoryFile (nPageSize, &m_hImpl); +} + +inline void OStoreFile::close (void) SAL_THROW(()) +{ + if (m_hImpl) + { + store_closeFile (m_hImpl); + m_hImpl = 0; + } +} + +inline storeError OStoreFile::flush (void) const SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_flushFile (m_hImpl); +} + +inline storeError OStoreFile::getRefererCount ( + sal_uInt32 &rnRefCount) const SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_getFileRefererCount (m_hImpl, &rnRefCount); +} + +inline storeError OStoreFile::getSize ( + sal_uInt32 &rnSize) const SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_getFileSize (m_hImpl, &rnSize); +} + +inline storeError OStoreFile::attrib ( + const rtl::OUString &rPath, + const rtl::OUString &rName, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 &rnAttrib) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_attrib ( + m_hImpl, rPath.pData, rName.pData, nMask1, nMask2, &rnAttrib); +} + +inline storeError OStoreFile::attrib ( + const rtl::OUString &rPath, + const rtl::OUString &rName, + sal_uInt32 nMask1, + sal_uInt32 nMask2) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_attrib ( + m_hImpl, rPath.pData, rName.pData, nMask1, nMask2, NULL); +} + +inline storeError OStoreFile::link ( + const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName, + const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_link ( + m_hImpl, + rSrcPath.pData, rSrcName.pData, + rDstPath.pData, rDstName.pData); +} + +inline storeError OStoreFile::symlink ( + const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName, + const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_symlink ( + m_hImpl, + rSrcPath.pData, rSrcName.pData, + rDstPath.pData, rDstName.pData); +} + +inline storeError OStoreFile::rename ( + const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName, + const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_rename ( + m_hImpl, + rSrcPath.pData, rSrcName.pData, + rDstPath.pData, rDstName.pData); +} + +inline storeError OStoreFile::remove ( + const rtl::OUString &rPath, const rtl::OUString &rName) SAL_THROW(()) +{ + if (!m_hImpl) + return store_E_InvalidHandle; + + return store_remove (m_hImpl, rPath.pData, rName.pData); +} + diff --git a/store/inc/store/types.h b/store/inc/store/types.h new file mode 100644 index 000000000000..17551381aca5 --- /dev/null +++ b/store/inc/store/types.h @@ -0,0 +1,170 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: types.h,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_TYPES_H_ +#define _STORE_TYPES_H_ "$Revision: 1.8 $" + +#include <sal/types.h> +#include <rtl/ustring.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** PageSize (recommended) default. + @see store_openFile() + */ +#define STORE_DEFAULT_PAGESIZE ((sal_uInt16)0x0400) + + +/** PageSize (enforced) limits. + @see store_openFile() + */ +#define STORE_MINIMUM_PAGESIZE ((sal_uInt16)0x0200) +#define STORE_MAXIMUM_PAGESIZE ((sal_uInt16)0x8000) + + +/** NameSize (enforced) limit. + @see any param pName + @see store_E_NameTooLong + */ +#define STORE_MAXIMUM_NAMESIZE 256 + + +/** Attributes (predefined). + @see store_attrib() + */ +#define STORE_ATTRIB_ISLINK ((sal_uInt32)0x10000000) +#define STORE_ATTRIB_ISDIR ((sal_uInt32)0x20000000) +#define STORE_ATTRIB_ISFILE ((sal_uInt32)0x40000000) + + +/** Access Mode enumeration. + @see store_openFile() + @see store_openDirectory() + @see store_openStream() + */ +enum __store_AccessMode +{ + store_AccessCreate, + store_AccessReadCreate, + store_AccessReadWrite, + store_AccessReadOnly, + store_Access_FORCE_EQUAL_SIZE = SAL_MAX_ENUM +}; + +/** Access Mode type. + */ +typedef enum __store_AccessMode storeAccessMode; + + +/** Error Code enumeration. + */ +enum __store_Error +{ + store_E_None = 0, + store_E_AccessViolation, + store_E_LockingViolation, + store_E_CantSeek, + store_E_CantRead, + store_E_CantWrite, + store_E_InvalidAccess, + store_E_InvalidHandle, + store_E_InvalidParameter, + store_E_InvalidChecksum, + store_E_AlreadyExists, + store_E_NotExists, + store_E_NotDirectory, + store_E_NotFile, + store_E_NoMoreFiles, + store_E_NameTooLong, + store_E_OutOfMemory, + store_E_OutOfSpace, + store_E_Pending, + store_E_WrongFormat, + store_E_WrongVersion, + store_E_Unknown, + store_E_FORCE_EQUAL_SIZE = SAL_MAX_ENUM +}; + +/** Error Code type. + */ +typedef enum __store_Error storeError; + + +/** Find Data structure. + @see store_findFirst() + @see store_findNext() + */ +struct __store_FindData +{ + /** Name. + @see m_nLength + */ + sal_Unicode m_pszName[STORE_MAXIMUM_NAMESIZE]; + + /** Name Length. + @see m_pszName + */ + sal_Int32 m_nLength; + + /** Attributes. + @see store_attrib() + */ + sal_uInt32 m_nAttrib; + + /** Size. + @see store_getStreamSize() + @see store_setStreamSize() + */ + sal_uInt32 m_nSize; + + /** Reserved for internal use. + */ + sal_uInt32 m_nReserved; +}; + +/** Find Data type. + */ +typedef struct __store_FindData storeFindData; + + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _STORE_TYPES_H_ */ + diff --git a/store/prj/build.lst b/store/prj/build.lst new file mode 100644 index 000000000000..938d95ebc029 --- /dev/null +++ b/store/prj/build.lst @@ -0,0 +1,5 @@ +s8 store : sal NULL +s8 store usr1 - all s8_mkout NULL +s8 store\inc nmake - all s8_inc NULL +s8 store\source nmake - all s8_source s8_inc NULL +s8 store\util nmake - all s8_util s8_source NULL diff --git a/store/prj/d.lst b/store/prj/d.lst new file mode 100644 index 000000000000..e39be093c53a --- /dev/null +++ b/store/prj/d.lst @@ -0,0 +1,13 @@ +mkdir: %_DEST%\inc%_EXT%\store +..\inc\store\*.h %_DEST%\inc%_EXT%\store\*.h +..\inc\store\store.hxx %_DEST%\inc%_EXT%\store\store.hxx +..\inc\store\store.inl %_DEST%\inc%_EXT%\store\store.inl +..\util\store.xml %_DEST%\xml%_EXT%\store.xml + +..\%__SRC%\lib\istore.lib %_DEST%\lib%_EXT%\istore.lib +..\%__SRC%\lib\libstore.*.* %_DEST%\lib%_EXT%\* +..\%__SRC%\bin\sto*.dll %_DEST%\bin%_EXT%\sto*.dll + + + +linklib: libstore.*.* diff --git a/store/source/lockbyte.cxx b/store/source/lockbyte.cxx new file mode 100644 index 000000000000..a03628bfb740 --- /dev/null +++ b/store/source/lockbyte.cxx @@ -0,0 +1,989 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: lockbyte.cxx,v $ + * + * $Revision: 1.1.2.4 $ + * + * last change: $Author: mhu $ $Date: 2008/11/25 15:44:56 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "lockbyte.hxx" + +#include "sal/types.h" +#include "osl/diagnose.h" +#include "osl/file.h" +#include "osl/process.h" +#include "rtl/alloc.h" +#include "rtl/ustring.hxx" + +#include "object.hxx" +#include "storbase.hxx" + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif + +using namespace store; + +/*======================================================================== + * + * ILockBytes (non-virtual interface) implementation. + * + *======================================================================*/ + +storeError ILockBytes::initialize (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + OSL_PRECOND((STORE_MINIMUM_PAGESIZE <= nPageSize) && (nPageSize <= STORE_MAXIMUM_PAGESIZE), "invalid PageSize"); + return initialize_Impl (rxAllocator, nPageSize); +} + +storeError ILockBytes::readPageAt (PageHolder & rPage, sal_uInt32 nOffset) +{ + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readPageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return readPageAt_Impl (rPage, nOffset); +} + +storeError ILockBytes::writePageAt (PageHolder const & rPage, sal_uInt32 nOffset) +{ + // [SECURITY:ValInput] + PageData const * pagedata = rPage.get(); + OSL_PRECOND(!(pagedata == 0), "store::ILockBytes::writePageAt(): invalid Page"); + if (pagedata == 0) + return store_E_InvalidParameter; + + sal_uInt32 const offset = pagedata->location(); + OSL_PRECOND(!(nOffset != offset), "store::ILockBytes::writePageAt(): inconsistent Offset"); + if (nOffset != offset) + return store_E_InvalidParameter; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writePageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return writePageAt_Impl (rPage, nOffset); +} + +storeError ILockBytes::readAt (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + // [SECURITY:ValInput] + sal_uInt8 * dst_lo = static_cast<sal_uInt8*>(pBuffer); + if (!(dst_lo != 0)) + return store_E_InvalidParameter; + + sal_uInt8 * dst_hi = dst_lo + nBytes; + if (!(dst_lo < dst_hi)) + return (dst_lo > dst_hi) ? store_E_InvalidParameter : store_E_None; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + sal_uInt64 const src_size = nOffset + nBytes; + if (src_size > SAL_MAX_UINT32) + return store_E_CantSeek; + + return readAt_Impl (nOffset, dst_lo, (dst_hi - dst_lo)); +} + +storeError ILockBytes::writeAt (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) +{ + // [SECURITY:ValInput] + sal_uInt8 const * src_lo = static_cast<sal_uInt8 const*>(pBuffer); + if (!(src_lo != 0)) + return store_E_InvalidParameter; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if (!(src_lo < src_hi)) + return (src_lo > src_hi) ? store_E_InvalidParameter : store_E_None; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writeAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + sal_uInt64 const dst_size = nOffset + nBytes; + if (dst_size > SAL_MAX_UINT32) + return store_E_CantSeek; + + return writeAt_Impl (nOffset, src_lo, (src_hi - src_lo)); +} + +storeError ILockBytes::getSize (sal_uInt32 & rnSize) +{ + rnSize = 0; + return getSize_Impl (rnSize); +} + +storeError ILockBytes::setSize (sal_uInt32 nSize) +{ + return setSize_Impl (nSize); +} + +storeError ILockBytes::flush() +{ + return flush_Impl(); +} + +storeError ILockBytes::lockRange (sal_uInt32 nOffset, sal_uInt32 nBytes) +{ + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::lockRange(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + sal_uInt64 size = nOffset + nBytes; + if (size > SAL_MAX_UINT32) + return store_E_CantSeek; + +#ifdef STORE_FEATURE_LOCKING + return lockRange_Impl (nOffset, nBytes); +#else + return store_E_None; // E_Unsupported +#endif /* STORE_FEATURE_LOCKING */ +} + +storeError ILockBytes::unlockRange (sal_uInt32 nOffset, sal_uInt32 nBytes) +{ + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::unlockRange(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + sal_uInt64 size = nOffset + nBytes; + if (size > SAL_MAX_UINT32) + return store_E_CantSeek; + +#ifdef STORE_FEATURE_LOCKING + return unlockRange_Impl (nOffset, nBytes); +#else + return store_E_None; // E_Unsupported +#endif /* STORE_FEATURE_LOCKING */ +} + +/*======================================================================== + * + * FileLockBytes implementation. + * + *======================================================================*/ +namespace store +{ + +struct FileHandle +{ + oslFileHandle m_handle; + + FileHandle() : m_handle(0) {} + + bool operator != (FileHandle const & rhs) + { + return (m_handle != rhs.m_handle); + } + + static storeError errorFromNative (oslFileError eErrno) + { + switch (eErrno) + { + case osl_File_E_None: + return store_E_None; + + case osl_File_E_NOENT: + return store_E_NotExists; + + case osl_File_E_ACCES: + case osl_File_E_PERM: + return store_E_AccessViolation; + + case osl_File_E_AGAIN: + case osl_File_E_DEADLK: + return store_E_LockingViolation; + + case osl_File_E_BADF: + return store_E_InvalidHandle; + + case osl_File_E_INVAL: + return store_E_InvalidParameter; + + case osl_File_E_NOMEM: + return store_E_OutOfMemory; + + case osl_File_E_NOSPC: + return store_E_OutOfSpace; + + case osl_File_E_OVERFLOW: + return store_E_CantSeek; + + default: + return store_E_Unknown; + } + } + + static sal_uInt32 modeToNative (storeAccessMode eAccessMode) + { + sal_uInt32 nFlags = 0; + switch (eAccessMode) + { + case store_AccessCreate: + case store_AccessReadCreate: + nFlags |= osl_File_OpenFlag_Create; + // fall through + case store_AccessReadWrite: + nFlags |= osl_File_OpenFlag_Write; + // fall through + case store_AccessReadOnly: + nFlags |= osl_File_OpenFlag_Read; + break; + default: + OSL_PRECOND(0, "store::FileHandle: unknown storeAccessMode"); + } + return nFlags; + } + + storeError initialize (rtl_uString * pFilename, storeAccessMode eAccessMode) + { + // Verify arguments. + sal_uInt32 nFlags = modeToNative (eAccessMode); + if (!pFilename || !nFlags) + return store_E_InvalidParameter; + + // Convert into FileUrl. + rtl::OUString aFileUrl; + if (osl_getFileURLFromSystemPath (pFilename, &(aFileUrl.pData)) != osl_File_E_None) + { + // Not system path. Assume file url. + rtl_uString_assign (&(aFileUrl.pData), pFilename); + } + if (aFileUrl.compareToAscii("file://", 7) != 0) + { + // Not file url. Assume relative path. + rtl::OUString aCwdUrl; + (void) osl_getProcessWorkingDir (&(aCwdUrl.pData)); + + // Absolute file url. + (void) osl_getAbsoluteFileURL (aCwdUrl.pData, aFileUrl.pData, &(aFileUrl.pData)); + } + + // Acquire handle. + oslFileError result = osl_openFile (aFileUrl.pData, &m_handle, nFlags); + if (result == osl_File_E_EXIST) + { + // Already existing (O_CREAT | O_EXCL). + result = osl_openFile (aFileUrl.pData, &m_handle, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + if ((result == osl_File_E_None) && (eAccessMode == store_AccessCreate)) + { + // Truncate existing file. + result = osl_setFileSize (m_handle, 0); + } + } + if (result != osl_File_E_None) + return errorFromNative(result); + return store_E_None; + } + + /** @see FileLockBytes destructor + */ + static void closeFile (oslFileHandle hFile) + { + (void) osl_closeFile (hFile); + } + + /** @see ResourceHolder<T>::destructor_type + */ + struct CloseFile + { + void operator()(FileHandle & rFile) const + { + // Release handle. + closeFile (rFile.m_handle); + rFile.m_handle = 0; + } + }; + typedef CloseFile destructor_type; +}; + +class FileLockBytes : + public store::OStoreObject, + public store::ILockBytes +{ + /** Representation. + */ + oslFileHandle m_hFile; + sal_uInt32 m_nSize; + rtl::Reference< PageData::Allocator > m_xAllocator; + + storeError initSize_Impl (sal_uInt32 & rnSize); + + /** ILockBytes implementation. + */ + virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); + + virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); + virtual storeError writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); + + virtual storeError getSize_Impl (sal_uInt32 & rnSize); + virtual storeError setSize_Impl (sal_uInt32 nSize); + + virtual storeError flush_Impl(); + + /** Not implemented. + */ + FileLockBytes (FileLockBytes const &); + FileLockBytes & operator= (FileLockBytes const &); + +public: + /** Construction. + */ + explicit FileLockBytes (FileHandle & rFile); + + /** Delegate multiple inherited IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + +protected: + /** Destruction. + */ + virtual ~FileLockBytes(); +}; + +} // namespace store + +FileLockBytes::FileLockBytes (FileHandle & rFile) + : m_hFile (rFile.m_handle), m_nSize (SAL_MAX_UINT32), m_xAllocator() +{ +} + +FileLockBytes::~FileLockBytes() +{ + FileHandle::closeFile (m_hFile); +} + +oslInterlockedCount SAL_CALL FileLockBytes::acquire() +{ + return OStoreObject::acquire(); +} + +oslInterlockedCount SAL_CALL FileLockBytes::release() +{ + return OStoreObject::release(); +} + +storeError FileLockBytes::initSize_Impl (sal_uInt32 & rnSize) +{ + /* osl_getFileSize() uses slow 'fstat(h, &size)', + * instead of fast 'size = lseek(h, 0, SEEK_END)'. + * so, init size here, and track changes. + */ + sal_uInt64 uSize = 0; + oslFileError result = osl_getFileSize (m_hFile, &uSize); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + if (uSize > SAL_MAX_UINT32) + return store_E_CantSeek; + + rnSize = sal::static_int_cast<sal_uInt32>(uSize); + return store_E_None; +} + +storeError FileLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + storeError result = initSize_Impl (m_nSize); + if (result != store_E_None) + return (result); + + result = PageData::Allocator::createInstance (rxAllocator, nPageSize); + if (result != store_E_None) + return (result); + + // @see readPageAt_Impl(). + m_xAllocator = rxAllocator; + return store_E_None; +} + +storeError FileLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) +{ + if (m_xAllocator.is()) + { + PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator); + page.swap (rPage); + } + + if (!m_xAllocator.is()) + return store_E_InvalidAccess; + if (!rPage.get()) + return store_E_OutOfMemory; + + PageData * pagedata = rPage.get(); + return readAt_Impl (nOffset, pagedata, pagedata->size()); +} + +storeError FileLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) +{ + PageData const * pagedata = rPage.get(); + OSL_PRECOND(pagedata != 0, "contract violation"); + return writeAt_Impl (nOffset, pagedata, pagedata->size()); +} + +storeError FileLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt64 nDone = 0; + oslFileError result = osl_readFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + if (nDone != nBytes) + return (nDone != 0) ? store_E_CantRead : store_E_NotExists; + return store_E_None; +} + +storeError FileLockBytes::writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt64 nDone = 0; + oslFileError result = osl_writeFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + if (nDone != nBytes) + return store_E_CantWrite; + + sal_uInt64 const uSize = nOffset + nBytes; + OSL_PRECOND(uSize < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation"); + if (uSize > m_nSize) + m_nSize = sal::static_int_cast<sal_uInt32>(uSize); + return store_E_None; +} + +storeError FileLockBytes::getSize_Impl (sal_uInt32 & rnSize) +{ + rnSize = m_nSize; + return store_E_None; +} + +storeError FileLockBytes::setSize_Impl (sal_uInt32 nSize) +{ + oslFileError result = osl_setFileSize (m_hFile, nSize); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + + m_nSize = nSize; + return store_E_None; +} + +storeError FileLockBytes::flush_Impl() +{ + oslFileError result = osl_syncFile (m_hFile); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + return store_E_None; +} + +/*======================================================================== + * + * MappedLockBytes implementation. + * + *======================================================================*/ +namespace store +{ + +struct FileMapping +{ + sal_uInt8 * m_pAddr; + sal_uInt32 m_nSize; + + FileMapping() : m_pAddr(0), m_nSize(0) {} + + bool operator != (FileMapping const & rhs) const + { + return ((m_pAddr != rhs.m_pAddr) || (m_nSize != rhs.m_nSize)); + } + + oslFileError initialize (oslFileHandle hFile) + { + // Determine mapping size. + sal_uInt64 uSize = 0; + oslFileError result = osl_getFileSize (hFile, &uSize); + if (result != osl_File_E_None) + return result; + + // [SECURITY:IntOver] + if (uSize > SAL_MAX_UINT32) + return osl_File_E_OVERFLOW; + m_nSize = sal::static_int_cast<sal_uInt32>(uSize); + + // Acquire mapping. + return osl_mapFile (hFile, reinterpret_cast<void**>(&m_pAddr), m_nSize, 0, osl_File_MapFlag_RandomAccess); + } + + /** @see MappedLockBytes::destructor. + */ + static void unmapFile (sal_uInt8 * pAddr, sal_uInt32 nSize) + { + (void) osl_unmapFile (pAddr, nSize); + } + + /** @see ResourceHolder<T>::destructor_type + */ + struct UnmapFile + { + void operator ()(FileMapping & rMapping) const + { + // Release mapping. + unmapFile (rMapping.m_pAddr, rMapping.m_nSize); + rMapping.m_pAddr = 0, rMapping.m_nSize = 0; + } + }; + typedef UnmapFile destructor_type; +}; + +class MappedLockBytes : + public store::OStoreObject, + public store::PageData::Allocator, + public store::ILockBytes +{ + /** Representation. + */ + sal_uInt8 * m_pData; + sal_uInt32 m_nSize; + sal_uInt16 m_nPageSize; + + /** PageData::Allocator implementation. + */ + virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize); + virtual void deallocate_Impl (void * pPage); + + /** ILockBytes implementation. + */ + virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); + + virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); + virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes); + + virtual storeError getSize_Impl (sal_uInt32 & rnSize); + virtual storeError setSize_Impl (sal_uInt32 nSize); + + virtual storeError flush_Impl(); + + /** Not implemented. + */ + MappedLockBytes (MappedLockBytes const &); + MappedLockBytes & operator= (MappedLockBytes const &); + +public: + /** Construction. + */ + explicit MappedLockBytes (FileMapping & rMapping); + + /** Delegate multiple inherited IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + +protected: + /* Destruction. + */ + virtual ~MappedLockBytes(); +}; + +} // namespace store + +MappedLockBytes::MappedLockBytes (FileMapping & rMapping) + : m_pData (rMapping.m_pAddr), m_nSize (rMapping.m_nSize), m_nPageSize(0) +{ +} + +MappedLockBytes::~MappedLockBytes() +{ + FileMapping::unmapFile (m_pData, m_nSize); +} + +oslInterlockedCount SAL_CALL MappedLockBytes::acquire() +{ + return OStoreObject::acquire(); +} + +oslInterlockedCount SAL_CALL MappedLockBytes::release() +{ + return OStoreObject::release(); +} + +void MappedLockBytes::allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) +{ + OSL_PRECOND((ppPage != 0) && (pnSize != 0), "contract violation"); + *ppPage = 0, *pnSize = m_nPageSize; +} + +void MappedLockBytes::deallocate_Impl (void * pPage) +{ + OSL_PRECOND((m_pData <= pPage) && (pPage < m_pData + m_nSize), "contract violation"); + (void)pPage; // UNUSED +} + +storeError MappedLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + rxAllocator = this; + m_nPageSize = nPageSize; + return store_E_None; +} + +storeError MappedLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) +{ + sal_uInt8 * src_lo = m_pData + nOffset; + if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) + return store_E_NotExists; + + sal_uInt8 * src_hi = src_lo + m_nPageSize; + if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) + return store_E_CantRead; + + PageHolder page (reinterpret_cast< PageData* >(src_lo), static_cast< PageData::Allocator* >(this)); + page.swap (rPage); + + return store_E_None; +} + +storeError MappedLockBytes::writePageAt_Impl (PageHolder const & /*rPage*/, sal_uInt32 /*nOffset*/) +{ + return store_E_AccessViolation; +} + +storeError MappedLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt8 const * src_lo = m_pData + nOffset; + if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) + return store_E_NotExists; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) + return store_E_CantRead; + + memcpy (pBuffer, src_lo, (src_hi - src_lo)); + return store_E_None; +} + +storeError MappedLockBytes::writeAt_Impl (sal_uInt32 /*nOffset*/, void const * /*pBuffer*/, sal_uInt32 /*nBytes*/) +{ + return store_E_AccessViolation; +} + +storeError MappedLockBytes::getSize_Impl (sal_uInt32 & rnSize) +{ + rnSize = m_nSize; + return store_E_None; +} + +storeError MappedLockBytes::setSize_Impl (sal_uInt32 /*nSize*/) +{ + return store_E_AccessViolation; +} + +storeError MappedLockBytes::flush_Impl() +{ + return store_E_None; +} + +/*======================================================================== + * + * MemoryLockBytes implementation. + * + *======================================================================*/ +namespace store +{ + +class MemoryLockBytes : + public store::OStoreObject, + public store::ILockBytes +{ + /** Representation. + */ + sal_uInt8 * m_pData; + sal_uInt32 m_nSize; + rtl::Reference< PageData::Allocator > m_xAllocator; + + /** ILockBytes implementation. + */ + virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); + + virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); + virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes); + + virtual storeError getSize_Impl (sal_uInt32 & rnSize); + virtual storeError setSize_Impl (sal_uInt32 nSize); + + virtual storeError flush_Impl(); + + /** Not implemented. + */ + MemoryLockBytes (MemoryLockBytes const &); + MemoryLockBytes& operator= (MemoryLockBytes const &); + +public: + /** Construction. + */ + MemoryLockBytes(); + + /** Delegate multiple inherited IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + +protected: + /** Destruction. + */ + virtual ~MemoryLockBytes(); +}; + +} // namespace store + +MemoryLockBytes::MemoryLockBytes() + : m_pData (0), m_nSize (0), m_xAllocator() +{} + +MemoryLockBytes::~MemoryLockBytes() +{ + rtl_freeMemory (m_pData); +} + +oslInterlockedCount SAL_CALL MemoryLockBytes::acquire (void) +{ + return OStoreObject::acquire(); +} + +oslInterlockedCount SAL_CALL MemoryLockBytes::release (void) +{ + return OStoreObject::release(); +} + +storeError MemoryLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + storeError result = PageData::Allocator::createInstance (rxAllocator, nPageSize); + if (result == store_E_None) + { + // @see readPageAt_Impl(). + m_xAllocator = rxAllocator; + } + return result; +} + +storeError MemoryLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) +{ + if (m_xAllocator.is()) + { + PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator); + page.swap (rPage); + } + + if (!m_xAllocator.is()) + return store_E_InvalidAccess; + if (!rPage.get()) + return store_E_OutOfMemory; + + PageData * pagedata = rPage.get(); + return readAt_Impl (nOffset, pagedata, pagedata->size()); +} + +storeError MemoryLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) +{ + PageData const * pagedata = rPage.get(); + OSL_PRECOND(!(pagedata == 0), "contract violation"); + return writeAt_Impl (nOffset, pagedata, pagedata->size()); +} + +storeError MemoryLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt8 const * src_lo = m_pData + nOffset; + if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) + return store_E_NotExists; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) + return store_E_CantRead; + + memcpy (pBuffer, src_lo, (src_hi - src_lo)); + return store_E_None; +} + +storeError MemoryLockBytes::writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt64 const dst_size = nOffset + nBytes; + OSL_PRECOND(dst_size < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation"); + if (dst_size > m_nSize) + { + storeError eErrCode = setSize_Impl (sal::static_int_cast<sal_uInt32>(dst_size)); + if (eErrCode != store_E_None) + return eErrCode; + } + OSL_POSTCOND(dst_size <= m_nSize, "store::MemoryLockBytes::setSize_Impl() contract violation"); + + sal_uInt8 * dst_lo = m_pData + nOffset; + if (dst_lo >= m_pData + m_nSize) + return store_E_CantSeek; + + sal_uInt8 * dst_hi = dst_lo + nBytes; + if (dst_hi > m_pData + m_nSize) + return store_E_CantWrite; + + memcpy (dst_lo, pBuffer, (dst_hi - dst_lo)); + return store_E_None; +} + +storeError MemoryLockBytes::getSize_Impl (sal_uInt32 & rnSize) +{ + rnSize = m_nSize; + return store_E_None; +} + +storeError MemoryLockBytes::setSize_Impl (sal_uInt32 nSize) +{ + if (nSize != m_nSize) + { + sal_uInt8 * pData = reinterpret_cast<sal_uInt8*>(rtl_reallocateMemory (m_pData, nSize)); + if (pData != 0) + { + if (nSize > m_nSize) + memset (pData + m_nSize, 0, sal::static_int_cast<size_t>(nSize - m_nSize)); + } + else + { + if (nSize != 0) + return store_E_OutOfMemory; + } + m_pData = pData, m_nSize = nSize; + } + return store_E_None; +} + +storeError MemoryLockBytes::flush_Impl() +{ + return store_E_None; +} + +/*======================================================================== + * + * ILockBytes factory implementations. + * + *======================================================================*/ +namespace store +{ + +template< class T > struct ResourceHolder +{ + typedef typename T::destructor_type destructor_type; + + T m_value; + + explicit ResourceHolder (T const & value = T()) : m_value (value) {} + ~ResourceHolder() { reset(); } + + T & get() { return m_value; } + T const & get() const { return m_value; } + + void set (T const & value) { m_value = value; } + void reset (T const & value = T()) + { + T tmp (m_value); + if (tmp != value) + destructor_type()(tmp); + set (value); + } + T release() + { + T tmp (m_value); + set (T()); + return tmp; + } + + ResourceHolder (ResourceHolder & rhs) + { + set (rhs.release()); + } + ResourceHolder & operator= (ResourceHolder & rhs) + { + reset (rhs.release()); + return *this; + } +}; + +storeError +FileLockBytes_createInstance ( + rtl::Reference< ILockBytes > & rxLockBytes, + rtl_uString * pFilename, + storeAccessMode eAccessMode +) +{ + // Acquire file handle. + ResourceHolder<FileHandle> xFile; + storeError result = xFile.get().initialize (pFilename, eAccessMode); + if (result != store_E_None) + return (result); + + if (eAccessMode == store_AccessReadOnly) + { + ResourceHolder<FileMapping> xMapping; + if (xMapping.get().initialize (xFile.get().m_handle) == osl_File_E_None) + { + rxLockBytes = new MappedLockBytes (xMapping.get()); + if (!rxLockBytes.is()) + return store_E_OutOfMemory; + (void) xMapping.release(); + } + } + if (!rxLockBytes.is()) + { + rxLockBytes = new FileLockBytes (xFile.get()); + if (!rxLockBytes.is()) + return store_E_OutOfMemory; + (void) xFile.release(); + } + + return store_E_None; +} + +storeError +MemoryLockBytes_createInstance ( + rtl::Reference< ILockBytes > & rxLockBytes +) +{ + rxLockBytes = new MemoryLockBytes(); + if (!rxLockBytes.is()) + return store_E_OutOfMemory; + + return store_E_None; +} + +} // namespace store diff --git a/store/source/lockbyte.hxx b/store/source/lockbyte.hxx new file mode 100644 index 000000000000..20a8b0b77073 --- /dev/null +++ b/store/source/lockbyte.hxx @@ -0,0 +1,222 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: lockbyte.hxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: mhu $ $Date: 2008/09/18 16:10:50 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef _STORE_LOCKBYTE_HXX_ +#define _STORE_LOCKBYTE_HXX_ "$Revision: 1.1.2.1 $" + +#ifndef _SAL_TYPES_H_ +#include "sal/types.h" +#endif + +#ifndef _RTL_REF_HXX_ +#include "rtl/ref.hxx" +#endif +#ifndef _RTL_USTRING_H_ +#include "rtl/ustring.h" +#endif + +#ifndef _STORE_TYPES_H_ +#include "store/types.h" +#endif +#ifndef _STORE_STORBASE_HXX_ +#include "storbase.hxx" +#endif + +namespace store +{ + +/*======================================================================== + * + * ILockBytes interface. + * + *======================================================================*/ +class ILockBytes : public rtl::IReference +{ +public: + /** + @param rxAllocator [out] + @param nPageSize [in] + */ + storeError initialize ( + rtl::Reference< PageData::Allocator > & rxAllocator, + sal_uInt16 nPageSize); + + /** + @param rPage [out] + @param nOffset [in] + */ + storeError readPageAt ( + PageHolder & rPage, + sal_uInt32 nOffset); + + /** + @param rPage [in] + @param nOffset [in] + */ + storeError writePageAt ( + PageHolder const & rPage, + sal_uInt32 nOffset); + + /** + @param nOffset [in] + @param pBuffer [out] + @param nBytes [in] + @return store_E_None upon success + */ + storeError readAt ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes); + + /** + @param nOffset [in] + @param pBuffer [in] + @param nBytes [in] + @return store_E_None upon success + */ + storeError writeAt ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes); + + /** + @param rnSize [out] + @return store_E_None upon success + */ + storeError getSize (sal_uInt32 & rnSize); + + /** + @param nSize [in] + @return store_E_None upon success + */ + storeError setSize (sal_uInt32 nSize); + + /** + @return store_E_None upon success + */ + storeError flush(); + + /** + @param nOffset [in] + @param nBytes [in] + @return store_E_None upon success + store_E_LockingViolation + */ + storeError lockRange ( + sal_uInt32 nOffset, + sal_uInt32 nBytes); + + /** + @param nOffset [in] + @param nBytes [in] + @return store_E_None upon success + store_E_LockingViolation + */ + storeError unlockRange ( + sal_uInt32 nOffset, + sal_uInt32 nBytes); + +private: + /** Implementation (abstract). + */ + virtual storeError initialize_Impl ( + rtl::Reference< PageData::Allocator > & rxAllocator, + sal_uInt16 nPageSize) = 0; + + virtual storeError readPageAt_Impl ( + PageHolder & rPage, + sal_uInt32 nOffset) = 0; + + virtual storeError writePageAt_Impl ( + PageHolder const & rPage, + sal_uInt32 nOffset) = 0; + + virtual storeError readAt_Impl ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes) = 0; + + virtual storeError writeAt_Impl ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes) = 0; + + virtual storeError getSize_Impl ( + sal_uInt32 & rnSize) = 0; + + virtual storeError setSize_Impl ( + sal_uInt32 nSize) = 0; + + virtual storeError flush_Impl() = 0; + +#ifdef STORE_FEATURE_LOCKING + virtual storeError lockRange_Impl ( + sal_uInt32 nOffset, + sal_uInt32 nBytes) = 0; + + virtual storeError unlockRange_Impl ( + sal_uInt32 nOffset, + sal_uInt32 nBytes) = 0; +#endif /* STORE_FEATURE_LOCKING */ +}; + +/*======================================================================== + * + * ILockBytes factories. + * + *======================================================================*/ + +storeError +FileLockBytes_createInstance ( + rtl::Reference< store::ILockBytes > & rxLockBytes, + rtl_uString * pFilename, + storeAccessMode eAccessMode +); + +storeError +MemoryLockBytes_createInstance ( + rtl::Reference< store::ILockBytes > & rxLockBytes +); + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_LOCKBYTE_HXX_ */ + diff --git a/store/source/makefile.mk b/store/source/makefile.mk new file mode 100644 index 000000000000..88b7b4af4c33 --- /dev/null +++ b/store/source/makefile.mk @@ -0,0 +1,75 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.5 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=.. + +PRJNAME=store +TARGET=store + +# --- Settings --- + +.INCLUDE : settings.mk + +# --- Files --- + +SLOFILES= \ + $(SLO)$/object.obj \ + $(SLO)$/lockbyte.obj \ + $(SLO)$/storbase.obj \ + $(SLO)$/storbios.obj \ + $(SLO)$/storcach.obj \ + $(SLO)$/stordata.obj \ + $(SLO)$/stordir.obj \ + $(SLO)$/storlckb.obj \ + $(SLO)$/stortree.obj \ + $(SLO)$/storpage.obj \ + $(SLO)$/store.obj + +.IF "$(debug)" != "" +OBJFILES= \ + $(OBJ)$/object.obj \ + $(OBJ)$/lockbyte.obj \ + $(OBJ)$/storbase.obj \ + $(OBJ)$/storbios.obj \ + $(OBJ)$/storcach.obj \ + $(OBJ)$/stordata.obj \ + $(OBJ)$/stordir.obj \ + $(OBJ)$/storlckb.obj \ + $(OBJ)$/stortree.obj \ + $(OBJ)$/storpage.obj \ + $(OBJ)$/store.obj + +.ENDIF # debug + +# --- Targets --- + +.INCLUDE : target.mk + diff --git a/store/source/object.cxx b/store/source/object.cxx new file mode 100644 index 000000000000..38bea6a331f3 --- /dev/null +++ b/store/source/object.cxx @@ -0,0 +1,115 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: object.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "object.hxx" + +#include "sal/types.h" +#include "rtl/alloc.h" +#include "rtl/ref.hxx" +#include "osl/diagnose.h" +#include "osl/interlck.h" + +namespace store +{ + +/*======================================================================== + * + * OStoreObject implementation. + * + *======================================================================*/ +const sal_uInt32 OStoreObject::m_nTypeId = sal_uInt32(0x58190322); + +/* + * OStoreObject. + */ +OStoreObject::OStoreObject (void) + : m_nRefCount (0) +{ +} + +/* + * ~OStoreObject. + */ +OStoreObject::~OStoreObject (void) +{ + OSL_ASSERT(m_nRefCount == 0); +} + +/* + * operator new. + */ +void* OStoreObject::operator new (size_t n) +{ + return rtl_allocateMemory (n); +} + +/* + * operator delete. + */ +void OStoreObject::operator delete (void *p, size_t) +{ + rtl_freeMemory (p); +} + +/* + * isKindOf. + */ +sal_Bool SAL_CALL OStoreObject::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == m_nTypeId); +} + +/* + * acquire. + */ +oslInterlockedCount SAL_CALL OStoreObject::acquire (void) +{ + oslInterlockedCount result = osl_incrementInterlockedCount (&m_nRefCount); + return (result); +} + +/* + * release. + */ +oslInterlockedCount SAL_CALL OStoreObject::release (void) +{ + oslInterlockedCount result = osl_decrementInterlockedCount (&m_nRefCount); + if (result == 0) + { + // Last reference released. + delete this; + } + return (result); +} + +} // namespace store diff --git a/store/source/object.hxx b/store/source/object.hxx new file mode 100644 index 000000000000..bc2a9bbcffe8 --- /dev/null +++ b/store/source/object.hxx @@ -0,0 +1,146 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: object.hxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: mhu $ $Date: 2008/09/18 16:10:51 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef _STORE_OBJECT_HXX_ +#define _STORE_OBJECT_HXX_ "$Revision: 1.1.2.1 $" + +#ifndef _SAL_TYPES_H_ +#include "sal/types.h" +#endif + +#ifndef _RTL_REF_HXX_ +#include "rtl/ref.hxx" +#endif + +#ifndef _OSL_INTERLCK_H_ +#include "osl/interlck.h" +#endif + +namespace store +{ + +/*======================================================================== + * + * IStoreHandle interface. + * + *======================================================================*/ +class IStoreHandle : public rtl::IReference +{ +public: + /** Replaces dynamic_cast type checking. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId) = 0; +}; + + +/** Template helper function as dynamic_cast replacement. + */ +template<class store_handle_type> +store_handle_type * SAL_CALL query ( + IStoreHandle * pHandle, store_handle_type *); + +/*======================================================================== + * + * OStoreObject interface. + * + *======================================================================*/ +class OStoreObject : public store::IStoreHandle +{ + /** Template function specialization as dynamic_cast replacement. + */ + friend OStoreObject* + SAL_CALL query<> (IStoreHandle *pHandle, OStoreObject*); + +public: + /** Construction. + */ + OStoreObject (void); + + /** Allocation. + */ + static void* operator new (size_t n); + static void operator delete (void *p, size_t); + + /** IStoreHandle. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId); + + /** IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire (void); + virtual oslInterlockedCount SAL_CALL release (void); + +protected: + /** Destruction. + */ + virtual ~OStoreObject (void); + +private: + /** The IStoreHandle TypeId. + */ + static const sal_uInt32 m_nTypeId; + + /** Representation. + */ + oslInterlockedCount m_nRefCount; + + /** Not implemented. + */ + OStoreObject (const OStoreObject&); + OStoreObject& operator= (const OStoreObject&); +}; + +/** Template function specialization as dynamic_cast replacement. + */ +template<> inline OStoreObject* +SAL_CALL query (IStoreHandle *pHandle, OStoreObject*) +{ + if (pHandle && pHandle->isKindOf (OStoreObject::m_nTypeId)) + { + // Handle is kind of OStoreObject. + return static_cast<OStoreObject*>(pHandle); + } + return 0; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_OBJECT_HXX_ */ diff --git a/store/source/storbase.cxx b/store/source/storbase.cxx new file mode 100644 index 000000000000..747b70df393a --- /dev/null +++ b/store/source/storbase.cxx @@ -0,0 +1,205 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storbase.cxx,v $ + * + * $Revision: 1.12.8.4 $ + * + * last change: $Author: mhu $ $Date: 2008/10/31 18:28:18 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storbase.hxx" + +#include "sal/types.h" +#include "rtl/alloc.h" +#include "rtl/ref.hxx" +#include "osl/diagnose.h" + +#include "store/types.h" +#include "object.hxx" + +#ifndef INCLUDED_STDIO_H +#include <stdio.h> +#define INCLUDED_STDIO_H +#endif + +using namespace store; + +/*======================================================================== + * + * SharedCount::Allocator. + * + *======================================================================*/ +SharedCount::Allocator & +SharedCount::Allocator::get() +{ + static Allocator g_aSharedCountAllocator; + return g_aSharedCountAllocator; +} + +SharedCount::Allocator::Allocator() +{ + m_cache = rtl_cache_create ( + "store_shared_count_cache", + sizeof(long), + 0, // objalign + 0, // constructor + 0, // destructor + 0, // reclaim + 0, // userarg + 0, // default source + 0 // flags + ); +} + +SharedCount::Allocator::~Allocator() +{ + rtl_cache_destroy (m_cache), m_cache = 0; +} + +/*======================================================================== + * + * PageData::Allocator_Impl (default allocator). + * + *======================================================================*/ +namespace store +{ + +class PageData::Allocator_Impl : + public store::OStoreObject, + public store::PageData::Allocator +{ +public: + /** Construction (two phase). + */ + Allocator_Impl(); + + storeError initialize (sal_uInt16 nPageSize); + + /** Delegate multiple inherited rtl::IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire() + { + return OStoreObject::acquire(); + } + virtual oslInterlockedCount SAL_CALL release() + { + return OStoreObject::release(); + } + +protected: + /** Destruction. + */ + virtual ~Allocator_Impl(); + +private: + /** Representation. + */ + rtl_cache_type * m_page_cache; + sal_uInt16 m_page_size; + + /** PageData::Allocator implementation. + */ + virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize); + virtual void deallocate_Impl (void * pPage); + + /** Not implemented. + */ + Allocator_Impl (Allocator_Impl const &); + Allocator_Impl & operator= (Allocator_Impl const &); +}; + +} // namespace store + +PageData::Allocator_Impl::Allocator_Impl() + : m_page_cache(0), m_page_size(0) +{} + +storeError +PageData::Allocator_Impl::initialize (sal_uInt16 nPageSize) +{ + char name[RTL_CACHE_NAME_LENGTH + 1]; + sal_Size size = sal::static_int_cast< sal_Size >(nPageSize); + (void) snprintf (name, sizeof(name), "store_page_alloc_%lu", size); + + m_page_cache = rtl_cache_create (name, size, 0, 0, 0, 0, 0, 0, 0); + if (!m_page_cache) + return store_E_OutOfMemory; + + m_page_size = nPageSize; + return store_E_None; +} + +PageData::Allocator_Impl::~Allocator_Impl() +{ + rtl_cache_destroy(m_page_cache), m_page_cache = 0; +} + +void PageData::Allocator_Impl::allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) +{ + OSL_PRECOND((ppPage != 0) && (pnSize != 0), "contract violation"); + *ppPage = rtl_cache_alloc(m_page_cache), *pnSize = m_page_size; +} + +void PageData::Allocator_Impl::deallocate_Impl (void * pPage) +{ + OSL_PRECOND(pPage != 0, "contract violation"); + rtl_cache_free(m_page_cache, pPage); +} + +/*======================================================================== + * + * PageData::Allocator factory. + * + *======================================================================*/ + +storeError +PageData::Allocator::createInstance (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + rtl::Reference< PageData::Allocator_Impl > xAllocator (new PageData::Allocator_Impl()); + if (!xAllocator.is()) + return store_E_OutOfMemory; + + rxAllocator = &*xAllocator; + return xAllocator->initialize (nPageSize); +} + +/*======================================================================== + * + * OStorePageObject. + * + *======================================================================*/ +/* + * ~OStorePageObject. + */ +OStorePageObject::~OStorePageObject (void) +{ +} diff --git a/store/source/storbase.hxx b/store/source/storbase.hxx new file mode 100644 index 000000000000..04be2860f691 --- /dev/null +++ b/store/source/storbase.hxx @@ -0,0 +1,974 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storbase.hxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORBASE_HXX_ +#define _STORE_STORBASE_HXX_ "$Revision: 1.10.8.4 $" + +#include "sal/types.h" + +#include "rtl/alloc.h" +#include "rtl/crc.h" +#include "rtl/ref.hxx" + +#include "osl/diagnose.h" +#include "osl/endian.h" + +#include "store/types.h" + +#ifndef INCLUDED_STDDEF_H +#include <stddef.h> +#define INCLUDED_STDDEF_H +#endif + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif + +/*======================================================================== + * + * store common internals. + * + *======================================================================*/ + +#ifndef STORE_IMPL_ISP2 +#define STORE_IMPL_ISP2(value) (((value) & ((value) - 1)) == 0) +#endif + +#ifndef STORE_IMPL_CONCAT +#define STORE_IMPL_CONCAT(x, y) STORE_IMPL_CONCAT2(x,y) +#define STORE_IMPL_CONCAT2(x, y) x##y +#endif + +#ifndef STORE_STATIC_ASSERT /* Compile time assertion */ +namespace store +{ + template< bool x > struct STATIC_ASSERTION_FAILURE; + template<> struct STATIC_ASSERTION_FAILURE< true > { enum { value = 1 }; }; + + template< int x > struct static_assert_test{}; +} // namespace store + +#define STORE_STATIC_ASSERT(pred) \ +typedef \ +store::static_assert_test< sizeof( store::STATIC_ASSERTION_FAILURE< (bool)(pred) > ) > \ +STORE_IMPL_CONCAT(static_assert_typedef_, __LINE__) + +#endif /* !STORE_STATIC_ASSERT */ + +namespace store +{ + +#ifdef htons +#undef htons +#endif +#ifdef ntohs +#undef ntohs +#endif + +#ifdef htonl +#undef htonl +#endif +#ifdef ntohl +#undef ntohl +#endif + +#ifdef OSL_BIGENDIAN +inline sal_uInt16 htons (sal_uInt16 h) { return OSL_SWAPWORD(h); } +inline sal_uInt16 ntohs (sal_uInt16 n) { return OSL_SWAPWORD(n); } + +inline sal_uInt32 htonl (sal_uInt32 h) { return OSL_SWAPDWORD(h); } +inline sal_uInt32 ntohl (sal_uInt32 n) { return OSL_SWAPDWORD(n); } +#else +inline sal_uInt16 htons (sal_uInt16 h) { return (h); } +inline sal_uInt16 ntohs (sal_uInt16 n) { return (n); } + +inline sal_uInt32 htonl (sal_uInt32 h) { return (h); } +inline sal_uInt32 ntohl (sal_uInt32 n) { return (n); } +#endif /* OSL_BIGENDIAN */ + +/** swap. + */ +template< typename T > void swap (T & lhs, T & rhs) +{ + T tmp = lhs; lhs = rhs; rhs = tmp; +} + +/*======================================================================== + * + * SharedCount. + * + *======================================================================*/ +class SharedCount +{ + long * m_pCount; + + class Allocator + { + rtl_cache_type * m_cache; + + public: + static Allocator & get(); + + long * alloc() + { + return static_cast<long*>(rtl_cache_alloc (m_cache)); + } + void free (long * pCount) + { + rtl_cache_free (m_cache, pCount); + } + + protected: + Allocator(); + ~Allocator(); + }; + +public: + SharedCount() + : m_pCount(Allocator::get().alloc()) + { + if (m_pCount != 0) (*m_pCount) = 1; + } + + ~SharedCount() + { + if (m_pCount != 0) + { + long new_count = --(*m_pCount); + if (new_count == 0) + Allocator::get().free(m_pCount); + } + } + + void swap (SharedCount & rhs) // nothrow + { + store::swap(m_pCount, rhs.m_pCount); + } + + SharedCount (SharedCount const & rhs) // nothrow + : m_pCount (rhs.m_pCount) + { + if (m_pCount != 0) ++(*m_pCount); + } + SharedCount & operator= (SharedCount const & rhs) // nothrow + { + SharedCount tmp(rhs); + swap(tmp); + return *this; + } + + bool operator== (long count) const + { + return (m_pCount != 0) ? *m_pCount == count : false; + } +}; + +/*======================================================================== + * + * OStorePageGuard. + * + *======================================================================*/ +struct OStorePageGuard +{ + /** Representation. + */ + sal_uInt32 m_nMagic; + sal_uInt32 m_nCRC32; + + /** Construction. + */ + explicit OStorePageGuard (sal_uInt32 nMagic = 0, sal_uInt32 nCRC32 = 0) + : m_nMagic (store::htonl(nMagic)), + m_nCRC32 (store::htonl(nCRC32)) + {} + + void swap (OStorePageGuard & rhs) + { + store::swap(m_nMagic, rhs.m_nMagic); + store::swap(m_nCRC32, rhs.m_nCRC32); + } + + OStorePageGuard (OStorePageGuard const & rhs) + : m_nMagic (rhs.m_nMagic), + m_nCRC32 (rhs.m_nCRC32) + {} + + OStorePageGuard& operator= (const OStorePageGuard& rhs) + { + m_nMagic = rhs.m_nMagic; + m_nCRC32 = rhs.m_nCRC32; + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageGuard& rhs) const + { + return ((m_nMagic == rhs.m_nMagic) && + (m_nCRC32 == rhs.m_nCRC32) ); + } +}; + +/*======================================================================== + * + * OStorePageDescriptor. + * + *======================================================================*/ +#define STORE_PAGE_NULL ((sal_uInt32)(~0)) + +struct OStorePageDescriptor +{ + /** Representation. + */ + sal_uInt32 m_nAddr; + sal_uInt16 m_nSize; + sal_uInt16 m_nUsed; + + /** Construction. + */ + explicit OStorePageDescriptor ( + sal_uInt32 nAddr = STORE_PAGE_NULL, + sal_uInt16 nSize = 0, + sal_uInt16 nUsed = 0) + : m_nAddr (store::htonl(nAddr)), + m_nSize (store::htons(nSize)), + m_nUsed (store::htons(nUsed)) + {} + + void swap (OStorePageDescriptor & rhs) + { + store::swap(m_nAddr, rhs.m_nAddr); + store::swap(m_nSize, rhs.m_nSize); + store::swap(m_nUsed, rhs.m_nUsed); + } + + OStorePageDescriptor (const OStorePageDescriptor & rhs) + : m_nAddr (rhs.m_nAddr), + m_nSize (rhs.m_nSize), + m_nUsed (rhs.m_nUsed) + {} + + OStorePageDescriptor & operator= (const OStorePageDescriptor & rhs) + { + m_nAddr = rhs.m_nAddr; + m_nSize = rhs.m_nSize; + m_nUsed = rhs.m_nUsed; + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageDescriptor & rhs) const + { + return ((m_nAddr == rhs.m_nAddr) && + (m_nSize == rhs.m_nSize) ); + } + + bool operator<= (const OStorePageDescriptor & rhs) const + { + return ((m_nAddr == rhs.m_nAddr ) && + (store::ntohs(m_nSize) <= store::ntohs(rhs.m_nSize)) ); + } + + bool operator< (const OStorePageDescriptor & rhs) const + { + if (m_nAddr == rhs.m_nAddr) + return (store::ntohs(m_nSize) < store::ntohs(rhs.m_nSize)); + else + return (store::ntohl(m_nAddr) < store::ntohl(rhs.m_nAddr)); + } +}; + +/*======================================================================== + * + * OStorePageKey. + * + *======================================================================*/ +struct OStorePageKey +{ + /** Representation. + */ + sal_uInt32 m_nLow; + sal_uInt32 m_nHigh; + + /** Construction. + */ + explicit OStorePageKey (sal_uInt32 nLow = 0, sal_uInt32 nHigh = 0) + : m_nLow (store::htonl(nLow)), + m_nHigh (store::htonl(nHigh)) + {} + + void swap (OStorePageKey & rhs) + { + store::swap(m_nLow, rhs.m_nLow); + store::swap(m_nHigh, rhs.m_nHigh); + } + + OStorePageKey (const OStorePageKey & rhs) + : m_nLow (rhs.m_nLow), m_nHigh (rhs.m_nHigh) + {} + + OStorePageKey & operator= (const OStorePageKey & rhs) + { + m_nLow = rhs.m_nLow; + m_nHigh = rhs.m_nHigh; + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageKey & rhs) const + { + return ((m_nLow == rhs.m_nLow ) && + (m_nHigh == rhs.m_nHigh) ); + } + + bool operator< (const OStorePageKey & rhs) const + { + if (m_nHigh == rhs.m_nHigh) + return (store::ntohl(m_nLow) < store::ntohl(rhs.m_nLow)); + else + return (store::ntohl(m_nHigh) < store::ntohl(rhs.m_nHigh)); + } +}; + +/*======================================================================== + * + * OStorePageLink. + * + *======================================================================*/ +struct OStorePageLink +{ + /** Representation. + */ + sal_uInt32 m_nAddr; + + /** Construction. + */ + explicit OStorePageLink (sal_uInt32 nAddr = STORE_PAGE_NULL) + : m_nAddr (store::htonl(nAddr)) + {} + + void swap (OStorePageLink & rhs) + { + store::swap(m_nAddr, rhs.m_nAddr); + } + + OStorePageLink (const OStorePageLink & rhs) + : m_nAddr (rhs.m_nAddr) + {} + + OStorePageLink & operator= (const OStorePageLink & rhs) + { + m_nAddr = rhs.m_nAddr; + return *this; + } + + OStorePageLink & operator= (sal_uInt32 nAddr) + { + m_nAddr = store::htonl(nAddr); + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageLink & rhs) const + { + return (m_nAddr == rhs.m_nAddr); + } + + bool operator< (const OStorePageLink& rhs) const + { + return (store::ntohl(m_nAddr) < store::ntohl(rhs.m_nAddr)); + } + + /** Operation. + */ + sal_uInt32 location() const + { + return store::ntohl(m_nAddr); + } + + void link (OStorePageLink & rPred) + { + // @@@ swap (rPred); @@@ + OStorePageLink tmp (rPred); + rPred = *this; + *this = tmp; + } + + void unlink (OStorePageLink& rPred) + { + rPred = *this; + *this = OStorePageLink(); + } +}; + +/*======================================================================== + * + * PageData. + * + *======================================================================*/ +typedef struct PageData OStorePageData; // backward compat. +struct PageData +{ + typedef OStorePageGuard G; + typedef OStorePageDescriptor D; + typedef OStorePageLink L; + + /** Representation. + */ + G m_aGuard; + D m_aDescr; + L m_aMarked; + L m_aUnused; + + /** theSize. + */ + static const size_t theSize = sizeof(G) + sizeof(D) + 2 * sizeof(L); + static const sal_uInt16 thePageSize = theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize); + + /** location. + */ + sal_uInt32 location() const + { + return store::ntohl(m_aDescr.m_nAddr); + } + void location (sal_uInt32 nAddr) + { + m_aDescr.m_nAddr = store::htonl(nAddr); + } + + /** size. + */ + sal_uInt16 size() const + { + return store::ntohs(m_aDescr.m_nSize); + } + + /** type. + */ + sal_uInt32 type() const + { + return store::ntohl(m_aGuard.m_nMagic); + } + + /** Allocation. + */ + class Allocator_Impl; + class Allocator : public rtl::IReference + { + public: + template< class T > T * construct() + { + void * page = 0; sal_uInt16 size = 0; + if (allocate (&page, &size)) + { + return new(page) T(size); + } + return 0; + } + + bool allocate (void ** ppPage, sal_uInt16 * pnSize) + { + allocate_Impl (ppPage, pnSize); + return ((*ppPage != 0) && (*pnSize != 0)); + } + + void deallocate (void * pPage) + { + if (pPage != 0) + deallocate_Impl (pPage); + } + + static storeError createInstance ( + rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + private: + /** Implementation (abstract). + */ + virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) = 0; + virtual void deallocate_Impl (void * pPage) = 0; + }; + + static void* operator new (size_t, void * p) { return p; } + static void operator delete (void * , void *) {} + + /** Construction. + */ + explicit PageData (sal_uInt16 nPageSize = thePageSize) + : m_aGuard(), + m_aDescr(STORE_PAGE_NULL, nPageSize, thePageSize), + m_aMarked(), + m_aUnused() + {} + + void swap (PageData & rhs) // nothrow + { + m_aGuard.swap(rhs.m_aGuard); + m_aDescr.swap(rhs.m_aDescr); + m_aMarked.swap(rhs.m_aMarked); + m_aUnused.swap(rhs.m_aUnused); + } + + PageData (PageData const & rhs) // nothrow + : m_aGuard (rhs.m_aGuard), + m_aDescr (rhs.m_aDescr), + m_aMarked(rhs.m_aMarked), + m_aUnused(rhs.m_aUnused) + {} + + PageData & operator= (PageData const & rhs) // nothrow + { + PageData tmp (rhs); + swap (tmp); + return *this; + } + + /** guard (external representation). + */ + void guard() + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + void guard (sal_uInt32 nAddr) + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + m_aDescr.m_nAddr = store::htonl(nAddr); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } + storeError verify (sal_uInt32 nAddr) const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + if (m_aDescr.m_nAddr != store::htonl(nAddr)) + return store_E_InvalidAccess; + return store_E_None; + } + + storeError verifyVersion (sal_uInt32 nMagic) const + { + if (m_aGuard.m_nMagic != store::htonl(nMagic)) + return store_E_WrongVersion; + else + return store_E_None; + } +}; + +/*======================================================================== + * + * PageHolder. + * + *======================================================================*/ +class PageHolder +{ + SharedCount m_refcount; + PageData * m_pagedata; + + typedef rtl::Reference< PageData::Allocator > allocator_type; + allocator_type m_allocator; + +public: + explicit PageHolder (PageData * pagedata = 0, allocator_type const & allocator = allocator_type()) + : m_refcount (), + m_pagedata (pagedata), + m_allocator(allocator) + { + OSL_ENSURE((m_pagedata == 0) || m_allocator.is(), "store::PageHolder::ctor(): pagedata w/o allocator."); + } + + ~PageHolder() + { + if ((m_refcount == 1) && (m_pagedata != 0)) + { + // free pagedata. + OSL_ENSURE(m_allocator.is(), "store::PageHolder::dtor(): pagedata w/o allocator."); + m_allocator->deallocate (m_pagedata); + } + } + + void swap (PageHolder & rhs) // nothrow + { + m_refcount.swap(rhs.m_refcount); + store::swap(m_pagedata, rhs.m_pagedata); + store::swap(m_allocator, rhs.m_allocator); + } + + PageHolder (PageHolder const & rhs) // nothrow + : m_refcount (rhs.m_refcount), + m_pagedata (rhs.m_pagedata), + m_allocator(rhs.m_allocator) + {} + + PageHolder & operator= (PageHolder const & rhs) // nothrow + { + PageHolder tmp (rhs); + swap(tmp); + return *this; + } + + PageData * get() { return m_pagedata; } + PageData const * get() const { return m_pagedata; } + + PageData * operator->() + { + OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator->(): Null pointer"); + return m_pagedata; + } + PageData const * operator->() const + { + OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator->(): Null pointer"); + return m_pagedata; + } + + PageData & operator*() + { + OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator*(): Null pointer"); + return *m_pagedata; + } + PageData const & operator*() const + { + OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator*(): Null pointer"); + return *m_pagedata; + } +}; + +/*======================================================================== + * + * PageHolderObject. + * + *======================================================================*/ +template< class T > +class PageHolderObject +{ + /** Representation. + */ + PageHolder m_xPage; + + /** Checked cast. + */ + template< class U > + static bool isA (PageData const * p) + { + return ((p != 0) && (p->type() == U::theTypeId)); + } + + template< class U > + static U * dynamic_page_cast (PageData * p) + { + return isA<U>(p) ? static_cast<U*>(p) : 0; + } + + template< class U > + static U const * dynamic_page_cast (PageData const * p) + { + return isA<U>(p) ? static_cast<U const *>(p) : 0; + } + +public: + bool construct (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + if ((m_xPage.get() == 0) && rxAllocator.is()) + { + PageHolder tmp (rxAllocator->construct<T>(), rxAllocator); + m_xPage.swap (tmp); + } + return (m_xPage.get() != 0); + } + + static PageHolderObject<T> createInstance (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + PageHolderObject<T> tmp; + (void) tmp.construct (rxAllocator); + return tmp; + } + + explicit PageHolderObject (PageHolder const & rxPage = PageHolder()) + : m_xPage (rxPage) + {} + + void swap (PageHolderObject<T> & rhs) + { + m_xPage.swap (rhs.m_xPage); + } + + PageHolderObject (PageHolderObject<T> const & rhs) + : m_xPage (rhs.m_xPage) + {} + + PageHolderObject<T> & operator= (PageHolderObject<T> const & rhs) + { + PageHolderObject<T> tmp (rhs); + this->swap (tmp); + return *this; + } + + bool is() const + { + return (m_xPage.get() != 0); + } + +#if 1 /* EXP */ + PageHolder & get() { return m_xPage; } + PageHolder const & get() const { return m_xPage; } +#endif /* EXP */ + + T * operator->() + { + T * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return pImpl; + } + T const * operator->() const + { + T const * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return pImpl; + } + + T & operator*() + { + T * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return (*pImpl); + } + T const & operator*() const + { + T const * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return (*pImpl); + } + + static storeError guard (PageHolder & rxPage, sal_uInt32 nAddr) + { + PageData * pHead = rxPage.get(); + if (!pHead) + return store_E_InvalidAccess; + pHead->guard(nAddr); + + T * pImpl = dynamic_page_cast<T>(pHead); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::guard(): Null pointer"); + pImpl->guard(); + + return store_E_None; + } + static storeError verify (PageHolder const & rxPage, sal_uInt32 nAddr) + { + PageData const * pHead = rxPage.get(); + if (!pHead) + return store_E_InvalidAccess; + + storeError eErrCode = pHead->verify(nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + T const * pImpl = dynamic_page_cast<T>(pHead); + if (!pImpl) + return store_E_WrongVersion; + + return pImpl->verify(); + } +}; + +/*======================================================================== + * + * PageObject. + * + *======================================================================*/ +#if 1 /* EXP */ +class PageObject +{ +public: + explicit PageObject (PageHolder const & rxPage = PageHolder()) + : m_xPage (rxPage), m_bDirty (false) + {} + + virtual ~PageObject() + {} + + PageHolder & get() { return m_xPage; } + PageHolder const & get() const { return m_xPage; } + + void clean() { m_bDirty = false; } + void touch() { m_bDirty = true; } + + sal_uInt32 location() const + { + PageData const * pagedata = m_xPage.get(); + return (pagedata != 0) ? pagedata->location() : STORE_PAGE_NULL; + } + void location (sal_uInt32 nAddr) + { + PageData * pagedata = m_xPage.get(); + if (pagedata != 0) + pagedata->location (nAddr); + } + +protected: + PageHolder m_xPage; + bool m_bDirty; + + virtual storeError guard (sal_uInt32 nAddr) = 0; + virtual storeError verify (sal_uInt32 nAddr) const = 0; +}; +#endif /* EXP */ + +class OStorePageBIOS; + +class OStorePageObject +{ + typedef OStorePageData page; + +public: + /** Allocation. + */ + static void * operator new (size_t n) SAL_THROW(()) + { + return rtl_allocateMemory (sal_uInt32(n)); + } + static void operator delete (void * p, size_t) SAL_THROW(()) + { + rtl_freeMemory (p); + } + + /** State. + */ + inline bool dirty (void) const; + inline void clean (void); + inline void touch (void); + + /** Location. + */ + inline sal_uInt32 location (void) const; + inline void location (sal_uInt32 nAddr); + +protected: + /** Representation. + */ + PageHolder m_xPage; + bool m_bDirty; + + /** Construction. + */ + explicit OStorePageObject (PageHolder const & rxPage = PageHolder()) + : m_xPage (rxPage), m_bDirty (false) + {} + + /** Destruction. + */ + virtual ~OStorePageObject (void); + +public: + template< class U > + PageHolderObject<U> makeHolder() const + { + return PageHolderObject<U>(m_xPage); + } + + template< class U > + storeError construct (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + if (!rxAllocator.is()) + return store_E_InvalidAccess; + + PageHolder tmp (rxAllocator->construct<U>(), rxAllocator); + if (!tmp.get()) + return store_E_OutOfMemory; + + m_xPage.swap (tmp); + return store_E_None; + } + + + PageHolder & get() { return m_xPage; } + PageHolder const & get() const { return m_xPage; } + + virtual storeError guard (sal_uInt32 nAddr) = 0; + virtual storeError verify (sal_uInt32 nAddr) const = 0; +}; + +inline bool OStorePageObject::dirty (void) const +{ + return m_bDirty; +} + +inline void OStorePageObject::clean (void) +{ + m_bDirty = false; +} + +inline void OStorePageObject::touch (void) +{ + m_bDirty = true; +} + +inline sal_uInt32 OStorePageObject::location (void) const +{ + return m_xPage->location(); +} + +inline void OStorePageObject::location (sal_uInt32 nAddr) +{ + m_xPage->location(nAddr); + touch(); +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORBASE_HXX_ */ diff --git a/store/source/storbios.cxx b/store/source/storbios.cxx new file mode 100644 index 000000000000..d1f15dcda247 --- /dev/null +++ b/store/source/storbios.cxx @@ -0,0 +1,1570 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storbios.cxx,v $ + * + * $Revision: 1.1.2.3 $ + * + * last change: $Author: mhu $ $Date: 2008/10/31 18:28:18 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storbios.hxx" + +#include "sal/types.h" +#include "sal/macros.h" + +#include "rtl/alloc.h" +#include "rtl/ref.hxx" + +#include "osl/diagnose.h" +#include "osl/mutex.hxx" + +#include "store/types.h" +#include "object.hxx" +#include "lockbyte.hxx" +#include "storcach.hxx" + +using namespace store; + +/*======================================================================== + * + * OStoreSuperBlock. + * + *======================================================================*/ +#define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343) + +struct OStoreSuperBlock +{ + typedef OStorePageGuard G; + typedef OStorePageDescriptor D; + typedef OStorePageLink L; + + /** Representation. + */ + G m_aGuard; + D m_aDescr; + sal_uInt32 m_nMarked; + L m_aMarked; + sal_uInt32 m_nUnused; + L m_aUnused; + + /** theSize. + */ + static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32)); + + /** Construction. + */ + explicit OStoreSuperBlock (sal_uInt16 nPageSize) + : m_aGuard (STORE_MAGIC_SUPERBLOCK), + m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE), + m_nMarked (store::htonl(0)), + m_aMarked (0), + m_nUnused (store::htonl(0)), + m_aUnused (0) + {} + + OStoreSuperBlock (const OStoreSuperBlock& rOther) + : m_aGuard (rOther.m_aGuard), + m_aDescr (rOther.m_aDescr), + m_nMarked (rOther.m_nMarked), + m_aMarked (rOther.m_aMarked), + m_nUnused (rOther.m_nUnused), + m_aUnused (rOther.m_aUnused) + {} + + OStoreSuperBlock& operator= (const OStoreSuperBlock& rOther) + { + m_aGuard = rOther.m_aGuard; + m_aDescr = rOther.m_aDescr; + m_nMarked = rOther.m_nMarked; + m_aMarked = rOther.m_aMarked; + m_nUnused = rOther.m_nUnused; + m_aUnused = rOther.m_aUnused; + return *this; + } + + /** Comparison. + */ + sal_Bool operator== (const OStoreSuperBlock& rOther) const + { + return ((m_aGuard == rOther.m_aGuard ) && + (m_aDescr == rOther.m_aDescr ) && + (m_nMarked == rOther.m_nMarked) && + (m_aMarked == rOther.m_aMarked) && + (m_nUnused == rOther.m_nUnused) && + (m_aUnused == rOther.m_aUnused) ); + } + + /** unused(Count|Head|Insert|Remove|Reset). + */ + sal_uInt32 unusedCount (void) const + { + return store::ntohl(m_nUnused); + } + const L& unusedHead (void) const + { + return m_aUnused; + } + void unusedInsert (const L& rLink) + { + sal_uInt32 nUnused = unusedCount(); + m_nUnused = store::htonl(nUnused + 1); + m_aUnused = rLink; + } + void unusedRemove (const L& rLink) + { + sal_uInt32 nUnused = unusedCount(); + m_nUnused = store::htonl(nUnused - 1); + m_aUnused = rLink; + } + void unusedReset (void) + { + m_nUnused = store::htonl(0); + m_aUnused = L(0); + } + + /** guard (external representation). + */ + void guard() + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic); + if (nMagic != STORE_MAGIC_SUPERBLOCK) + return store_E_WrongFormat; + + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } +}; + +/*======================================================================== + * + * OStoreStateBlock. + * + *======================================================================*/ +struct OStoreStateBlock +{ + enum StateBits + { + STATE_CLEAN = 0, + STATE_CLOSE_WAIT = 1, + STATE_FLUSH_WAIT = 2 + }; + + /** Representation. + */ + sal_uInt32 m_nState; + + /** theSize. + */ + static const size_t theSize = sizeof(sal_uInt32); + + /** Construction. + */ + OStoreStateBlock() + : m_nState (store::htonl(STATE_CLEAN)) + {} + + /** Operation. + */ + bool closePending (void) const + { + sal_uInt32 nState = store::ntohl(m_nState); + return ((nState & STATE_CLOSE_WAIT) == STATE_CLOSE_WAIT); + } + void closed (void) + { + sal_uInt32 nState = store::ntohl(m_nState); + nState &= ~STATE_CLOSE_WAIT; + m_nState = store::htonl(nState); + } + + bool flushPending (void) const + { + sal_uInt32 nState = store::ntohl(m_nState); + return ((nState & STATE_FLUSH_WAIT) == STATE_FLUSH_WAIT); + } + void flushed (void) + { + sal_uInt32 nState = store::ntohl(m_nState); + nState &= ~STATE_FLUSH_WAIT; + m_nState = store::htonl(nState); + } + + void modified (void) + { + sal_uInt32 nState = store::ntohl(m_nState); + nState |= (STATE_CLOSE_WAIT | STATE_FLUSH_WAIT); + m_nState = store::htonl(nState); + } + void clean (void) + { + sal_uInt32 nState = store::ntohl(m_nState); + nState &= ~(STATE_CLOSE_WAIT | STATE_FLUSH_WAIT); + m_nState = store::htonl(nState); + } +}; + +/*======================================================================== + * + * OStoreSuperBlockPage interface. + * + *======================================================================*/ +namespace store +{ + +struct OStoreSuperBlockPage +{ + typedef OStoreSuperBlock SuperBlock; + typedef OStoreStateBlock StateBlock; + + /** Representation. + */ + SuperBlock m_aSuperOne; + SuperBlock m_aSuperTwo; + StateBlock m_aState; + + /** theSize. + */ + static const size_t theSize = 2 * SuperBlock::theSize + StateBlock::theSize; + static const sal_uInt16 thePageSize = theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize); + + /** Allocation. + */ + static void * operator new (size_t n) SAL_THROW(()) + { + return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n)); + } + static void operator delete (void * p, size_t) SAL_THROW(()) + { + rtl_freeMemory (p); + } + + static void * operator new (size_t, sal_uInt16 nPageSize) SAL_THROW(()) + { + return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize)); + } + static void operator delete (void * p, sal_uInt16) SAL_THROW(()) + { + rtl_freeMemory (p); + } + + /** Construction. + */ + explicit OStoreSuperBlockPage (sal_uInt16 nPageSize = thePageSize) + : m_aSuperOne(nPageSize), + m_aSuperTwo(nPageSize), + m_aState() + {} + + /** guard (external representation). + */ + void guard() + { + m_aSuperOne.guard(); + m_aSuperTwo.guard(); + } + + /** save. + */ + storeError save (OStorePageBIOS &rBIOS) + { + // Guard. + guard(); + + // Write. + return rBIOS.write (0, this, theSize); + } + + /** close. + */ + storeError close ( + OStorePageBIOS &rBIOS); + + /** flush. + */ + storeError flush ( + OStorePageBIOS &rBIOS); + + /** modified. + */ + storeError modified ( + OStorePageBIOS &rBIOS); + + /** verify (with repair). + */ + storeError verify ( + OStorePageBIOS &rBIOS); +}; + +} // namespace store + +/*======================================================================== + * + * OStoreSuperBlockPage implementation. + * + *======================================================================*/ +/* + * close. + */ +storeError OStoreSuperBlockPage::close (OStorePageBIOS &rBIOS) +{ + storeError eErrCode = store_E_None; + if (m_aState.closePending()) + { + // Mark as modified. + m_aState.modified(); + + // Check access mode. + if (rBIOS.isWriteable()) + { + // Save StateBlock. + StateBlock aState (m_aState); + + // Mark as clean. + aState.clean(); + + // Write behind SuperBlock. + sal_uInt32 nAddr = 2 * SuperBlock::theSize; + eErrCode = rBIOS.write (nAddr, &aState, StateBlock::theSize); + } + + // Mark as clean. + m_aState.clean(); + } + return eErrCode; +} + +/* + * flush. + */ +storeError OStoreSuperBlockPage::flush (OStorePageBIOS &rBIOS) +{ + storeError eErrCode = store_E_None; + if (m_aState.flushPending()) + { + // Check access mode. + if (rBIOS.isWriteable()) + { + // Save StateBlock. + StateBlock aState (m_aState); + + // Mark as flushed. + aState.flushed(); + + // Write behind SuperBlock. + sal_uInt32 nAddr = 2 * SuperBlock::theSize; + eErrCode = rBIOS.write (nAddr, &aState, StateBlock::theSize); + } + + // Mark as flushed. + m_aState.flushed(); + } + return eErrCode; +} + +/* + * modified. + */ +storeError OStoreSuperBlockPage::modified (OStorePageBIOS &rBIOS) +{ + storeError eErrCode = store_E_None; + if (!m_aState.flushPending()) + { + // Mark as modified. + m_aState.modified(); + + // Check access mode. + if (rBIOS.isWriteable()) + { + // Save StateBlock. + StateBlock aState (m_aState); + + // Write behind SuperBlock. + sal_uInt32 nAddr = 2 * SuperBlock::theSize; + eErrCode = rBIOS.write (nAddr, &aState, StateBlock::theSize); + } + } + return eErrCode; +} + +/* + * verify (with repair). + */ +storeError OStoreSuperBlockPage::verify (OStorePageBIOS &rBIOS) +{ + // Verify 1st copy. + storeError eErrCode = m_aSuperOne.verify(); + if (eErrCode == store_E_None) + { + // Ok. Verify 2nd copy. + eErrCode = m_aSuperTwo.verify(); + if (eErrCode == store_E_None) + { + // Ok. Ensure identical copies (1st copy wins). + if (!(m_aSuperOne == m_aSuperTwo)) + { + // Different. Replace 2nd copy with 1st copy. + m_aSuperTwo = m_aSuperOne; + + // Write back. + if (rBIOS.isWriteable()) + eErrCode = rBIOS.write (0, this, theSize); + else + eErrCode = store_E_None; + } + } + else + { + // Failure. Replace 2nd copy with 1st copy. + m_aSuperTwo = m_aSuperOne; + + // Write back. + if (rBIOS.isWriteable()) + eErrCode = rBIOS.write (0, this, theSize); + else + eErrCode = store_E_None; + } + } + else + { + // Failure. Verify 2nd copy. + eErrCode = m_aSuperTwo.verify(); + if (eErrCode == store_E_None) + { + // Ok. Replace 1st copy with 2nd copy. + m_aSuperOne = m_aSuperTwo; + + // Write back. + if (rBIOS.isWriteable()) + eErrCode = rBIOS.write (0, this, theSize); + else + eErrCode = store_E_None; + } + else + { + // Double Failure. + OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.\n"); + } + } + + // Done. + return eErrCode; +} + +/*======================================================================== + * + * OStorePageBIOS::Ace implementation. + * + *======================================================================*/ +OStorePageBIOS::Ace::Ace() + : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0) +{} + +OStorePageBIOS::Ace::~Ace() +{ + m_next->m_prev = m_prev, m_prev->m_next = m_next; +} + +int +SAL_CALL OStorePageBIOS::Ace::constructor (void * obj, void * /* arg */) +{ + Ace * ace = static_cast<Ace*>(obj); + ace->m_next = ace->m_prev = ace; + return 1; +} + +OStorePageBIOS::Ace * +OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr) +{ + OStorePageBIOS::Ace * entry; + for (entry = head->m_next; entry != head; entry = entry->m_next) + { + if (entry->m_addr >= addr) + return entry; + } + return head; +} + +void +OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry) +{ + // insert entry at queue tail (before head). + entry->m_next = head; + entry->m_prev = head->m_prev; + head->m_prev = entry; + entry->m_prev->m_next = entry; +} + +/*======================================================================== + * + * OStorePageBIOS::AceCache interface. + * + *======================================================================*/ +namespace store +{ + +class OStorePageBIOS::AceCache +{ + rtl_cache_type * m_ace_cache; + +public: + static AceCache & get(); + + OStorePageBIOS::Ace * + create (sal_uInt32 addr, sal_uInt32 used = 1); + + void + destroy (OStorePageBIOS::Ace * ace); + +protected: + AceCache(); + ~AceCache(); +}; + +} // namespace store + +/*======================================================================== + * + * OStorePageBIOS::AceCache implementation. + * + *======================================================================*/ +extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*); + +OStorePageBIOS::AceCache & +OStorePageBIOS::AceCache::get() +{ + static AceCache g_ace_cache; + return g_ace_cache; +} + +OStorePageBIOS::AceCache::AceCache() +{ + m_ace_cache = rtl_cache_create ( + "store_ace_cache", + sizeof (OStorePageBIOS::Ace), + 0, // objalign + reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor), + 0, // destructor, + 0, // reclaim, + 0, // userarg, + 0, // default source, + 0 // flags + ); +} + +OStorePageBIOS::AceCache::~AceCache() +{ + rtl_cache_destroy (m_ace_cache), m_ace_cache = 0; +} + +OStorePageBIOS::Ace * +OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used) +{ + Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache)); + if (ace != 0) + { + // verify invariant state. + OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace)); + + // initialize. + ace->m_addr = addr; + ace->m_used = used; + } + return ace; +} + +void +OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace) +{ + if (ace != 0) + { + // remove from queue (if any). + ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next; + + // restore invariant state. + ace->m_next = ace->m_prev = ace; + + // return to cache. + rtl_cache_free (m_ace_cache, ace); + } +} + +/*======================================================================== + * + * OStorePageBIOS implementation. + * + *======================================================================*/ +/* + * OStorePageBIOS. + */ +OStorePageBIOS::OStorePageBIOS (void) + : m_xLockBytes (NULL), + m_pSuper (NULL), + m_bModified (sal_False), + m_bWriteable (sal_False) +{ +} + +/* + * ~OStorePageBIOS. + */ +OStorePageBIOS::~OStorePageBIOS (void) +{ + OStorePageBIOS::close(); +} + +/* + * verify (SuperBlock with repair). + * Internal: Precond: initialized, exclusive access. + */ +storeError OStorePageBIOS::verify (SuperPage *&rpSuper) +{ + // Check SuperBlock page allocation. + if (rpSuper == 0) + { + // Allocate. + if ((rpSuper = new SuperPage()) == 0) + return store_E_OutOfMemory; + + // Load (w/o verification). + storeError eErrCode = read (0, rpSuper, SuperPage::theSize); + if (eErrCode != store_E_None) + { + // Cleanup and fail. + delete rpSuper, rpSuper = 0; + return eErrCode; + } + + // Check SuperBlock state. + if (rpSuper->m_aState.closePending()) + OSL_TRACE("OStorePageBIOS::verify(): close pending.\n"); + + if (rpSuper->m_aState.flushPending()) + OSL_TRACE("OStorePageBIOS::verify(): flush pending.\n"); + } + + // Verify SuperBlock page (with repair). + return rpSuper->verify (*this); +} + +/* + * repair (SuperBlock). + * Internal: Precond: initialized, exclusive access. + */ +storeError OStorePageBIOS::repair (SuperPage *&rpSuper) +{ + // Acquire Lock. + storeError eErrCode = acquireLock (0, SuperPage::theSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Verify SuperBlock page (with repair). + eErrCode = verify (rpSuper); + if (eErrCode != store_E_None) + { + // Failure. + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // ReleaseLock. + return releaseLock (0, SuperPage::theSize); +} + +/* + * create (SuperBlock). + * Internal: Precond: initialized, exclusive access. + */ +storeError OStorePageBIOS::create (sal_uInt16 nPageSize) +{ + // Check (internal) precond. + OSL_PRECOND(m_xLockBytes.is(), "store::PageBIOS::create(): contract violation"); + + // Check PageSize. + if ((STORE_MINIMUM_PAGESIZE > nPageSize) || (nPageSize > STORE_MAXIMUM_PAGESIZE)) + return store_E_InvalidParameter; + nPageSize = ((nPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1)); + + // Acquire Lock. + storeError eErrCode = acquireLock (0, nPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Allocate SuperBlock page. + delete m_pSuper, m_pSuper = 0; + if ((m_pSuper = new(nPageSize) SuperPage(nPageSize)) == 0) + { + // Cleanup and fail. + releaseLock (0, nPageSize); + return store_E_OutOfMemory; + } + m_pSuper->guard(); + + // Create initial page (w/ SuperBlock). + eErrCode = m_xLockBytes->writeAt (0, m_pSuper, nPageSize); + if (eErrCode != store_E_None) + { + // Cleanup and fail. + releaseLock (0, nPageSize); + return eErrCode; + } + +#ifdef STORE_FEATURE_COMMIT + // Commit. + eErrCode = m_xLockBytes->flush(); + OSL_POSTCOND( + eErrCode == store_E_None, + "OStorePageBIOS::create(): flush failed"); +#endif /* STORE_FEATURE_COMMIT */ + + // Adjust modified state. + m_bModified = (eErrCode != store_E_None); + + // Release Lock and finish. + return releaseLock (0, nPageSize); +} + +/* + * initialize. + * Precond: none. + */ +storeError OStorePageBIOS::initialize ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check arguments. + storeError eErrCode = store_E_InvalidParameter; + if (!pLockBytes) + return eErrCode; + + // Cleanup. +#if 0 /* OLD */ + __STORE_DELETEZ (m_pAcl); /* @@@ */ +#endif /* OLD */ + delete m_pSuper, m_pSuper = 0; + + // Initialize. + m_xLockBytes = pLockBytes; + m_bModified = sal_False; + m_bWriteable = (!(eAccessMode == store_AccessReadOnly)); + + // Check access mode. + if (eAccessMode == store_AccessReadOnly) + { + // Verify SuperBlock page. + eErrCode = verify (m_pSuper); + } + else if (eAccessMode != store_AccessCreate) + { + // Verify (w/ repair) SuperBlock page. + eErrCode = repair (m_pSuper); + } + else + { + // Truncate to zero length. + eErrCode = m_xLockBytes->setSize(0); + if (eErrCode != store_E_None) + return eErrCode; + +#ifdef STORE_FEATURE_COMMIT + // Commit. + eErrCode = m_xLockBytes->flush(); + if (eErrCode != store_E_None) + return eErrCode; +#endif /* STORE_FEATURE_COMMIT */ + + // Mark as not existing. + eErrCode = store_E_NotExists; + } + + if (eErrCode != store_E_None) + { + // Check reason. + if (eErrCode != store_E_NotExists) + return eErrCode; + + // Check mode. + if (eAccessMode == store_AccessReadOnly) + return store_E_NotExists; + if (eAccessMode == store_AccessReadWrite) + return store_E_NotExists; + + // Create SuperBlock page. + eErrCode = create (rnPageSize); + } + if (eErrCode == store_E_None) + { + // Obtain modified state. + m_bModified = m_pSuper->m_aState.flushPending(); + + // Obtain page size. + rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize); + + // Create page allocator. + eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Create page cache. + eErrCode = PageCache_createInstance (m_xCache, rnPageSize); + } + return eErrCode; +} + +/* + * acquireLock. + * Low Level: Precond: initialized, exclusive access. + */ +storeError OStorePageBIOS::acquireLock ( + sal_uInt32 nAddr, sal_uInt32 nSize) +{ + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Acquire Lock. + return m_xLockBytes->lockRange (nAddr, nSize); +} + +/* + * releaseLock. + * Low Level: Precond: initialized, exclusive access. + */ +storeError OStorePageBIOS::releaseLock ( + sal_uInt32 nAddr, sal_uInt32 nSize) +{ + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Release Lock. + return m_xLockBytes->unlockRange (nAddr, nSize); +} + +/* + * read. + * Low Level: Precond: initialized, exclusive access. + */ +storeError OStorePageBIOS::read ( + sal_uInt32 nAddr, void *pData, sal_uInt32 nSize) +{ + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Read Page. + return m_xLockBytes->readAt (nAddr, pData, nSize); +} + +/* + * write. + * Low Level: Precond: initialized, writeable, exclusive access. + */ +storeError OStorePageBIOS::write ( + sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize) +{ + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + if (!m_bWriteable) + return store_E_AccessViolation; + + // Check modified state. + if (!m_bModified) + { + // Mark as modified. + m_bModified = sal_True; + + // Mark SuperBlock modified. + storeError eErrCode = m_pSuper->modified (*this); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Write Data. + return m_xLockBytes->writeAt (nAddr, pData, nSize); +} + +/* + * acquirePage. + * Precond: initialized. + */ +storeError OStorePageBIOS::acquirePage ( + const OStorePageDescriptor& rDescr, storeAccessMode eMode) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Check access mode. + if (!(m_bWriteable || (eMode == store_AccessReadOnly))) + return store_E_AccessViolation; + + // Find access control list entry. + Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr); + if (ace->m_addr == rDescr.m_nAddr) + { + // Acquire existing entry (with ShareDenyWrite). + if (eMode == store_AccessReadOnly) + ace->m_used += 1; + else + return store_E_AccessViolation; + } + else + { + // Insert new entry. + Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1); + if (!entry) + return store_E_OutOfMemory; + Ace::insert (ace, entry); + } + + // Increment total referer count and finish. + m_ace_head.m_used += 1; + return store_E_None; +} + +/* + * releasePage. + * Precond: initialized. + */ +storeError OStorePageBIOS::releasePage ( + const OStorePageDescriptor& rDescr, storeAccessMode /* eMode */) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Find access control list entry. + Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr); + if (ace->m_addr != rDescr.m_nAddr) + return store_E_NotExists; + + // Release existing entry. + if (ace->m_used > 1) + ace->m_used -= 1; + else + AceCache::get().destroy (ace); + + // Decrement total referer count and finish. + m_ace_head.m_used -= 1; + return store_E_None; +} + +/* + * getRefererCount. + * Precond: none. + */ +sal_uInt32 OStorePageBIOS::getRefererCount (void) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Obtain total referer count. + return m_ace_head.m_used; +} + +/* + * allocate. + * Precond: initialized, writeable. + */ +storeError OStorePageBIOS::allocate ( + OStorePageObject& rPage, Allocation eAlloc) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + if (!m_bWriteable) + return store_E_AccessViolation; + + // Acquire SuperBlock Lock. + storeError eErrCode = acquireLock (0, SuperPage::theSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Load SuperBlock and require good health. + eErrCode = verify (m_pSuper); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // Check allocation. + if (eAlloc != ALLOCATE_EOF) + { + // Check FreeList. + OStorePageLink aListHead (m_pSuper->m_aSuperTwo.unusedHead()); + if (aListHead.location()) + { + // Allocate from FreeList. + OStorePageData aPageHead (OStorePageData::theSize); + aPageHead.location (aListHead.location()); + + // Load PageHead. + eErrCode = peek (aPageHead); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // Verify FreeList head. + OSL_PRECOND( + aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL, + "OStorePageBIOS::allocate(): page not free"); + if (aPageHead.m_aUnused.location() == STORE_PAGE_NULL) + { + // Recovery: Reset FreeList. + m_pSuper->m_aSuperTwo.unusedReset(); + m_pSuper->m_aSuperOne = m_pSuper->m_aSuperTwo; + + // Save SuperBlock page. + eErrCode = m_pSuper->save (*this); + + // Release SuperBlock Lock. + releaseLock (0, SuperPage::theSize); + + // Recovery: Allocate from EOF. + if (eErrCode == store_E_None) + return allocate (rPage, ALLOCATE_EOF); + else + return store_E_Unknown; + } + + // Pop from FreeList. + aListHead = aPageHead.m_aUnused.location(); + rPage.get()->m_aUnused = STORE_PAGE_NULL; + + // Save page at PageHead location. + eErrCode = saveObjectAt_Impl (rPage, aPageHead.location()); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // Save SuperBlock page. + m_pSuper->m_aSuperTwo.unusedRemove (aListHead); + m_pSuper->m_aSuperOne = m_pSuper->m_aSuperTwo; + + eErrCode = m_pSuper->save (*this); + OSL_POSTCOND( + eErrCode == store_E_None, + "OStorePageBIOS::allocate(): SuperBlock save failed"); + + // Release SuperBlock Lock and finish. + return releaseLock (0, SuperPage::theSize); + } + } + + // Allocate from logical EOF. Determine physical EOF. + sal_uInt32 nPhysLen = STORE_PAGE_NULL; + eErrCode = m_xLockBytes->getSize (nPhysLen); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // Obtain logical EOF. + OStorePageDescriptor aDescr (m_pSuper->m_aSuperTwo.m_aDescr); + sal_uInt32 nLogLen = store::ntohl(aDescr.m_nAddr); + if (nLogLen == 0) + nLogLen = nPhysLen; /* backward compatibility */ + + if (!(nLogLen < nPhysLen)) + { + // Check modified state. + if (!m_bModified) + { + // Mark modified. + m_bModified = sal_True; + + // Mark SuperBlock modified. + eErrCode = m_pSuper->modified (*this); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + } + + // Resize. + sal_uInt32 nAlign = SAL_MIN (nPhysLen, STORE_MAXIMUM_PAGESIZE); + nPhysLen = ((nPhysLen + nAlign) / nAlign) * nAlign; + + eErrCode = m_xLockBytes->setSize (nPhysLen); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + } + + // Save page at logical EOF. + eErrCode = saveObjectAt_Impl (rPage, nLogLen); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // Save SuperBlock page. + nLogLen += store::ntohs(aDescr.m_nSize); + aDescr.m_nAddr = store::htonl(nLogLen); + + m_pSuper->m_aSuperTwo.m_aDescr = aDescr; + m_pSuper->m_aSuperOne = m_pSuper->m_aSuperTwo; + + eErrCode = m_pSuper->save (*this); + OSL_POSTCOND( + eErrCode == store_E_None, + "OStorePageBIOS::allocate(): SuperBlock save failed"); + + // Release SuperBlock Lock and finish. + return releaseLock (0, SuperPage::theSize); +} + +/* + * free. + * Precond: initialized, writeable. + */ +storeError OStorePageBIOS::free (OStorePageData & /* rData */, sal_uInt32 nAddr) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + if (!m_bWriteable) + return store_E_AccessViolation; + + // Acquire SuperBlock Lock. + storeError eErrCode = acquireLock (0, SuperPage::theSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Load SuperBlock and require good health. + eErrCode = verify (m_pSuper); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // Load PageHead. + OStorePageData aPageHead(OStorePageData::theSize); + aPageHead.location (nAddr); + + eErrCode = peek (aPageHead); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // Invalidate cache. + (void) m_xCache->removePageAt (nAddr); + + // Push onto FreeList. + OStorePageLink aListHead (m_pSuper->m_aSuperTwo.unusedHead()); + + aPageHead.m_aUnused.m_nAddr = aListHead.m_nAddr; + aListHead.m_nAddr = aPageHead.m_aDescr.m_nAddr; + + // Save PageHead. + eErrCode = poke (aPageHead); + if (eErrCode != store_E_None) + { + releaseLock (0, SuperPage::theSize); + return eErrCode; + } + + // Save SuperBlock page. + m_pSuper->m_aSuperTwo.unusedInsert (aListHead); + m_pSuper->m_aSuperOne = m_pSuper->m_aSuperTwo; + + eErrCode = m_pSuper->save (*this); + OSL_POSTCOND( + eErrCode == store_E_None, + "OStorePageBIOS::free(): SuperBlock save failed"); + + // Release SuperBlock Lock and finish. + return releaseLock (0, SuperPage::theSize); +} + +/* + * loadObjectAt. + * Precond: initialized, readable. + */ +storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + return loadObjectAt_Impl (rPage, nAddr); +} + +/* + * loadObjectAt_Impl. + * Internal: Precond: initialized, readable, exclusive access. + */ +storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr) +{ + storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr); + if (eErrCode != store_E_NotExists) + return eErrCode; + + // Read page. + eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Verify page. + eErrCode = rPage.verify (nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Mark page as clean. + rPage.clean(); + + // Cache page. + return m_xCache->insertPageAt (rPage.get(), nAddr); +} + +/* + * saveObjectAt. + * Precond: initialized, writeable. + */ +storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + if (!m_bWriteable) + return store_E_AccessViolation; + + // Save Page. + return saveObjectAt_Impl (rPage, nAddr); +} + +/* + * saveObjectAt_Impl. + * Internal: Precond: initialized, writeable, exclusive access. + */ +storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr) +{ + // Guard page (incl. set location). + storeError eErrCode = rPage.guard (nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Write page. + eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Mark page as clean. + rPage.clean(); + + // Cache page. + return m_xCache->updatePageAt (rPage.get(), nAddr); +} + +/* + * close. + * Precond: none. + */ +storeError OStorePageBIOS::close (void) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check referer count. + if (m_ace_head.m_used > 0) + { + // Report remaining referer count. + OSL_TRACE("store::PageBIOS::close(): referer count: %d\n", m_ace_head.m_used); +#if 1 /* NEW */ + for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next) + { + m_ace_head.m_used -= ace->m_used; + AceCache::get().destroy (ace); + } + OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::close(): logic error"); +#endif /* NEW */ + } + + // Check SuperBlock page. + storeError eErrCode = store_E_None; + if (m_pSuper) + { + // Release SuperBlock page. + eErrCode = m_pSuper->close (*this); + delete m_pSuper, m_pSuper = 0; + } + + // Release PageCache. + m_xCache.clear(); + + // Check LockBytes. + if (m_xLockBytes.is()) + { +#ifdef STORE_FEATURE_COMMIT + // Commit. + storeError result = m_xLockBytes->flush(); + if (eErrCode == store_E_None) + { + // Previous result(s) okay. Propagate next result. + eErrCode = result; + } +#endif /* STORE_FEATURE_COMMIT */ + + // Release LockBytes. + m_xLockBytes.clear(); + } + + // Done. + return eErrCode; +} + +/* + * flush. + * Precond: initialized. + */ +storeError OStorePageBIOS::flush (void) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Check mode and state. + storeError eErrCode = store_E_None; + if (!(m_bWriteable && m_bModified)) + return eErrCode; + + // Flush SuperBlock page. + eErrCode = m_pSuper->flush (*this); + + // Flush LockBytes. + storeError result = m_xLockBytes->flush(); + if (eErrCode == store_E_None) + { + // Previous result(s) okay. Propagate next result. + eErrCode = result; + } + + // Adjust modified state. + m_bModified = (eErrCode != store_E_None); + + // Done. + return eErrCode; +} + +/* + * size. + * Precond: initialized. + */ +storeError OStorePageBIOS::size (sal_uInt32 &rnSize) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Initialize [out] param. + rnSize = 0; + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Obtain LockBytes size. + return m_xLockBytes->getSize (rnSize); +} + +/* + * scanBegin. + * Precond: initialized. + */ +storeError OStorePageBIOS::scanBegin ( + ScanContext &rCtx, sal_uInt32 nMagic) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Initialize [out] param. + rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0); + rCtx.m_nSize = 0; + rCtx.m_nMagic = nMagic; + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Check SuperBlock page. + storeError eErrCode = verify (m_pSuper); + if (eErrCode != store_E_None) + { + // Damaged. Determine page size (NYI). + OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n"); + return eErrCode; + } + + // Setup Context descriptor. + rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr; + rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize; // @@@ ntoh @@@ + + // Setup Context size. + eErrCode = size (rCtx.m_nSize); + if (eErrCode != store_E_None) + rCtx.m_nSize = ((sal_uInt32)(~0)); + + // Done. + return store_E_None; +} + +/* + * scanNext. + * Precond: initialized. + */ +storeError OStorePageBIOS::scanNext ( + ScanContext &rCtx, OStorePageObject &rPage) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard (m_aMutex); + + // Check precond. + if (!m_xLockBytes.is()) + return store_E_InvalidAccess; + + // Setup PageHead. + OStorePageData aPageHead (OStorePageData::theSize); + + // Check context. + while (rCtx.isValid()) + { + // Assign next location. + aPageHead.location (rCtx.m_aDescr.m_nAddr); + rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize; + + // Load PageHead. + storeError eErrCode = peek (aPageHead); + if (eErrCode != store_E_None) + continue; + + // Check PageHead Magic number. + if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic) + continue; + + // Check PageHead Unused link. + if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL) + continue; + + // Load page. + eErrCode = loadObjectAt_Impl (rPage, aPageHead.location()); + if (eErrCode != store_E_None) + continue; + + // Deliver page. + return store_E_None; + } + + // Done. + return store_E_CantSeek; +} + +/* + * peek (PageHead). + * Internal: Precond: initialized, readable, exclusive access. + */ +storeError OStorePageBIOS::peek (OStorePageData &rData) +{ + // Read PageHead. + storeError eErrCode = read (rData.location(), &rData, OStorePageData::theSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Verify PageHead. + return rData.verify(); +} + +/* + * poke (PageHead). + * Internal: Precond: initialized, writeable, exclusive access. + */ +storeError OStorePageBIOS::poke (OStorePageData &rData) +{ + // Guard PageHead. + rData.guard(); + + // Write PageHead. + return write (rData.location(), &rData, OStorePageData::theSize); +} diff --git a/store/source/storbios.hxx b/store/source/storbios.hxx new file mode 100644 index 000000000000..d9a0f982bd3c --- /dev/null +++ b/store/source/storbios.hxx @@ -0,0 +1,302 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storbios.hxx,v $ + * + * $Revision: 1.1.2.3 $ + * + * last change: $Author: mhu $ $Date: 2008/10/31 18:28:18 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef _STORE_STORBIOS_HXX_ +#define _STORE_STORBIOS_HXX_ "$Revision: 1.1.2.3 $" + +#include "sal/types.h" +#include "rtl/ref.hxx" +#include "osl/mutex.hxx" + +#include "store/types.h" +#include "object.hxx" +#include "lockbyte.hxx" +#include "storbase.hxx" +#include "storcach.hxx" + +/*======================================================================== + * + * OStorePageBIOS. + * + *======================================================================*/ +namespace store +{ + +struct OStoreSuperBlockPage; + +class OStorePageBIOS : public store::OStoreObject +{ +public: + /** Construction. + */ + OStorePageBIOS (void); + + /** Conversion into Mutex& + */ + inline operator osl::Mutex& (void) const; + + /** Initialization. + * @param pLockBytes [in] + * @param eAccessMode [in] + * @param rnPageSize [inout] + * @return store_E_None upon success + */ + virtual storeError initialize ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize); + + rtl::Reference< PageData::Allocator > & allocator() + { + return m_xAllocator; + } + + /** acquireLock. + */ + storeError acquireLock ( + sal_uInt32 nAddr, sal_uInt32 nSize); + + /** releaseLock. + */ + storeError releaseLock ( + sal_uInt32 nAddr, sal_uInt32 nSize); + + /** read. + */ + storeError read ( + sal_uInt32 nAddr, void *pData, sal_uInt32 nSize); + + /** write. + */ + storeError write ( + sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize); + + /** isModified. + */ + inline bool isModified (void) const; + + /** isWriteable. + */ + inline bool isWriteable (void) const; + + /** isValid. + */ + inline sal_Bool isValid (void) const; + + /** Page Access. + */ + storeError acquirePage ( + const OStorePageDescriptor& rDescr, storeAccessMode eMode); + + storeError releasePage ( + const OStorePageDescriptor& rDescr, storeAccessMode eMode); + + sal_uInt32 getRefererCount (void); + + /** Page Allocation. + */ + enum Allocation + { + ALLOCATE_FIRST = 0, + ALLOCATE_BEST = 1, + ALLOCATE_EOF = 2 + }; + + storeError allocate ( + OStorePageObject& rPage, Allocation eAllocation = ALLOCATE_FIRST); + + storeError free ( + OStorePageData & /* rData */, sal_uInt32 nAddr); + + /** Page I/O. + */ + storeError loadObjectAt ( + OStorePageObject& rPage, sal_uInt32 nAddr); + + storeError saveObjectAt ( + OStorePageObject& rPage, sal_uInt32 nAddr); + + /** close. + * @return store_E_None upon success. + */ + storeError close (void); + + /** flush. + * @return store_E_None upon success. + */ + storeError flush (void); + + /** size. + */ + storeError size (sal_uInt32 &rnSize); + + /** ScanContext. + */ + struct ScanContext + { + /** Representation. + */ + OStorePageDescriptor m_aDescr; + sal_uInt32 m_nSize; + sal_uInt32 m_nMagic; + + /** Construction. + */ + inline ScanContext (void); + + /** isValid. + */ + inline bool isValid (void) const; + }; + + /** scanBegin. + */ + storeError scanBegin ( + ScanContext &rCtx, + sal_uInt32 nMagic = 0); + + /** scanNext. + */ + storeError scanNext ( + ScanContext &rCtx, + OStorePageObject &rPage); + +protected: + /** Destruction (OReference). + */ + virtual ~OStorePageBIOS (void); + +private: + /** Representation. + */ + rtl::Reference<ILockBytes> m_xLockBytes; + osl::Mutex m_aMutex; + + typedef OStoreSuperBlockPage SuperPage; + SuperPage *m_pSuper; + + bool m_bModified; + bool m_bWriteable; + + rtl::Reference< PageData::Allocator > m_xAllocator; + rtl::Reference< PageCache > m_xCache; + + /** Page Access (control). + */ +public: + struct Ace + { + Ace * m_next; + Ace * m_prev; + + sal_uInt32 m_addr; + sal_uInt32 m_used; + + Ace(); + ~Ace(); + + static int SAL_CALL constructor (void * obj, void * arg); + + static Ace * find (Ace * head, sal_uInt32 addr); + static void insert (Ace * head, Ace * entry); + }; + +private: + Ace m_ace_head; + + class AceCache; + + /** create (SuperBlock). + */ + storeError create (sal_uInt16 nPageSize); + + /** SuperBlock verification and repair. + */ + storeError verify (SuperPage *&rpSuper); + storeError repair (SuperPage *&rpSuper); + + /** Page Maintenance. + */ + storeError peek ( + OStorePageData &rData); + storeError poke ( + OStorePageData &rData); + + storeError loadObjectAt_Impl ( + OStorePageObject & rPage, sal_uInt32 nAddr); + storeError saveObjectAt_Impl ( + OStorePageObject & rPage, sal_uInt32 nAddr); + + /** Not implemented. + */ + OStorePageBIOS (const OStorePageBIOS&); + OStorePageBIOS& operator= (const OStorePageBIOS&); +}; + +inline OStorePageBIOS::operator osl::Mutex& (void) const +{ + return (osl::Mutex&)m_aMutex; +} +inline bool OStorePageBIOS::isModified (void) const +{ + return m_bModified; +} +inline bool OStorePageBIOS::isWriteable (void) const +{ + return m_bWriteable; +} +inline sal_Bool OStorePageBIOS::isValid (void) const +{ + return m_xLockBytes.is(); +} + +inline OStorePageBIOS::ScanContext::ScanContext (void) + : m_aDescr (0, 0, 0), m_nSize (0), m_nMagic (0) +{ +} +inline bool OStorePageBIOS::ScanContext::isValid (void) const +{ + return (m_aDescr.m_nAddr < m_nSize); +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORBIOS_HXX_ */ diff --git a/store/source/storcach.cxx b/store/source/storcach.cxx new file mode 100644 index 000000000000..6306784592e0 --- /dev/null +++ b/store/source/storcach.cxx @@ -0,0 +1,564 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storcach.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storcach.hxx" + +#include "sal/types.h" +#include "rtl/alloc.h" +#include "osl/diagnose.h" + +#include "store/types.h" +#include "object.hxx" +#include "storbase.hxx" + +#ifndef INCLUDED_STDDEF_H +#include <stddef.h> +#define INCLUDED_STDDEF_H +#endif + +using namespace store; + +/*======================================================================== + * + * PageCache (non-virtual interface) implementation. + * + *======================================================================*/ + +storeError PageCache::lookupPageAt (PageHolder & rxPage, sal_uInt32 nOffset) +{ + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::lookupPageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return lookupPageAt_Impl (rxPage, nOffset); +} + +storeError PageCache::insertPageAt (PageHolder const & rxPage, sal_uInt32 nOffset) +{ + // [SECURITY:ValInput] + PageData const * pagedata = rxPage.get(); + OSL_PRECOND(!(pagedata == 0), "store::PageCache::insertPageAt(): invalid Page"); + if (pagedata == 0) + return store_E_InvalidParameter; + + sal_uInt32 const offset = pagedata->location(); + OSL_PRECOND(!(nOffset != offset), "store::PageCache::insertPageAt(): inconsistent Offset"); + if (nOffset != offset) + return store_E_InvalidParameter; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::insertPageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return insertPageAt_Impl (rxPage, nOffset); +} + +storeError PageCache::updatePageAt (PageHolder const & rxPage, sal_uInt32 nOffset) +{ + // [SECURITY:ValInput] + PageData const * pagedata = rxPage.get(); + OSL_PRECOND(!(pagedata == 0), "store::PageCache::updatePageAt(): invalid Page"); + if (pagedata == 0) + return store_E_InvalidParameter; + + sal_uInt32 const offset = pagedata->location(); + OSL_PRECOND(!(nOffset != offset), "store::PageCache::updatePageAt(): inconsistent Offset"); + if (nOffset != offset) + return store_E_InvalidParameter; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::updatePageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return updatePageAt_Impl (rxPage, nOffset); +} + +storeError PageCache::removePageAt (sal_uInt32 nOffset) +{ + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::removePageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return removePageAt_Impl (nOffset); +} + +/*======================================================================== + * + * Entry. + * + *======================================================================*/ +namespace +{ + +struct Entry +{ + /** Representation. + */ + PageHolder m_xPage; + sal_uInt32 m_nOffset; + Entry * m_pNext; + + /** Allocation. + */ + static void * operator new (size_t, void * p) { return p; } + static void operator delete (void *, void *) {} + + /** Construction. + */ + explicit Entry (PageHolder const & rxPage = PageHolder(), sal_uInt32 nOffset = STORE_PAGE_NULL) + : m_xPage(rxPage), m_nOffset(nOffset), m_pNext(0) + {} + + /** Destruction. + */ + ~Entry() {} +}; + +} // namespace + +/*======================================================================== + * + * EntryCache interface. + * + *======================================================================*/ +namespace +{ + +class EntryCache +{ + rtl_cache_type * m_entry_cache; + +public: + static EntryCache & get(); + + Entry * create (PageHolder const & rxPage, sal_uInt32 nOffset); + + void destroy (Entry * entry); + +protected: + EntryCache(); + ~EntryCache(); +}; + +} // namespace + +/*======================================================================== + * + * EntryCache implementation. + * + *======================================================================*/ + +EntryCache & EntryCache::get() +{ + static EntryCache g_entry_cache; + return g_entry_cache; +} + +EntryCache::EntryCache() +{ + m_entry_cache = rtl_cache_create ( + "store_cache_entry_cache", + sizeof(Entry), + 0, // objalign + 0, // constructor + 0, // destructor + 0, // reclaim + 0, // userarg + 0, // default source + 0 // flags + ); +} + +EntryCache::~EntryCache() +{ + rtl_cache_destroy (m_entry_cache), m_entry_cache = 0; +} + +Entry * EntryCache::create (PageHolder const & rxPage, sal_uInt32 nOffset) +{ + void * pAddr = rtl_cache_alloc (m_entry_cache); + if (pAddr != 0) + { + // construct. + return new(pAddr) Entry (rxPage, nOffset); + } + return 0; +} + +void EntryCache::destroy (Entry * entry) +{ + if (entry != 0) + { + // destruct. + entry->~Entry(); + + // return to cache. + rtl_cache_free (m_entry_cache, entry); + } +} + +/*======================================================================== + * + * highbit():= log2() + 1 (complexity O(1)) + * + *======================================================================*/ +static int highbit(sal_Size n) +{ + register int k = 1; + + if (n == 0) + return (0); +#if SAL_TYPES_SIZEOFLONG == 8 + if (n & 0xffffffff00000000ul) + k |= 32, n >>= 32; +#endif + if (n & 0xffff0000) + k |= 16, n >>= 16; + if (n & 0xff00) + k |= 8, n >>= 8; + if (n & 0xf0) + k |= 4, n >>= 4; + if (n & 0x0c) + k |= 2, n >>= 2; + if (n & 0x02) + k++; + + return (k); +} + +/*======================================================================== + * + * PageCache_Impl implementation. + * + *======================================================================*/ +namespace store +{ + +class PageCache_Impl : + public store::OStoreObject, + public store::PageCache +{ + /** Representation. + */ + static size_t const theTableSize = 32; + STORE_STATIC_ASSERT(STORE_IMPL_ISP2(theTableSize)); + + Entry ** m_hash_table; + Entry * m_hash_table_0[theTableSize]; + size_t m_hash_size; + size_t m_hash_shift; + size_t const m_page_shift; + + size_t m_hash_entries; // total number of entries in table. + size_t m_nHit; + size_t m_nMissed; + + inline int hash_Impl(sal_uInt32 a, size_t s, size_t q, size_t m) + { + return ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m)); + } + inline int hash_index_Impl (sal_uInt32 nOffset) + { + return hash_Impl(nOffset, m_hash_shift, m_page_shift, m_hash_size - 1); + } + + Entry * lookup_Impl (Entry * entry, sal_uInt32 nOffset); + void rescale_Impl (sal_Size new_size); + + /** PageCache Implementation. + */ + virtual storeError lookupPageAt_Impl ( + PageHolder & rxPage, + sal_uInt32 nOffset); + + virtual storeError insertPageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset); + + virtual storeError updatePageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset); + + virtual storeError removePageAt_Impl ( + sal_uInt32 nOffset); + + /** Not implemented. + */ + PageCache_Impl (PageCache_Impl const &); + PageCache_Impl & operator= (PageCache_Impl const &); + +public: + /** Construction. + */ + explicit PageCache_Impl (sal_uInt16 nPageSize); + + /** Delegate multiple inherited IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + +protected: + /** Destruction. + */ + virtual ~PageCache_Impl (void); +}; + +} // namespace store + +PageCache_Impl::PageCache_Impl (sal_uInt16 nPageSize) + : m_hash_table (m_hash_table_0), + m_hash_size (theTableSize), + m_hash_shift (highbit(m_hash_size) - 1), + m_page_shift (highbit(nPageSize) - 1), + m_hash_entries (0), + m_nHit (0), + m_nMissed (0) +{ + static size_t const theSize = sizeof(m_hash_table_0) / sizeof(m_hash_table_0[0]); + STORE_STATIC_ASSERT(theSize == theTableSize); + memset(m_hash_table_0, 0, sizeof(m_hash_table_0)); +} + +PageCache_Impl::~PageCache_Impl() +{ + double s_x = 0.0, s_xx = 0.0; + sal_Size i, n = m_hash_size; + for (i = 0; i < n; i++) + { + int x = 0; + Entry * entry = m_hash_table[i]; + while (entry != 0) + { + m_hash_table[i] = entry->m_pNext, entry->m_pNext = 0; + EntryCache::get().destroy (entry); + entry = m_hash_table[i]; + x += 1; + } + s_x += double(x); + s_xx += double(x) * double(x); + } + double ave = s_x / double(n); + OSL_TRACE("ave hash chain length: %g", ave); + (void) ave; + + if (m_hash_table != m_hash_table_0) + { + rtl_freeMemory (m_hash_table); + m_hash_table = m_hash_table_0; + m_hash_size = theTableSize; + m_hash_shift = highbit(m_hash_size) - 1; + } + OSL_TRACE("Hits: %u, Misses: %u", m_nHit, m_nMissed); +} + +oslInterlockedCount PageCache_Impl::acquire() +{ + return OStoreObject::acquire(); +} + +oslInterlockedCount PageCache_Impl::release() +{ + return OStoreObject::release(); +} + +void PageCache_Impl::rescale_Impl (sal_Size new_size) +{ + sal_Size new_bytes = new_size * sizeof(Entry*); + Entry ** new_table = (Entry**)(rtl_allocateMemory(new_bytes)); + + if (new_table != 0) + { + Entry ** old_table = m_hash_table; + sal_Size old_size = m_hash_size; + + OSL_TRACE("ave chain length: %u, total entries: %u [old_size: %u, new_size: %u]", + m_hash_entries >> m_hash_shift, m_hash_entries, old_size, new_size); + + memset (new_table, 0, new_bytes); + + m_hash_table = new_table; + m_hash_size = new_size; + m_hash_shift = highbit(m_hash_size) - 1; + + sal_Size i; + for (i = 0; i < old_size; i++) + { + Entry * curr = old_table[i]; + while (curr != 0) + { + Entry * next = curr->m_pNext; + int index = hash_index_Impl(curr->m_nOffset); + curr->m_pNext = m_hash_table[index], m_hash_table[index] = curr; + curr = next; + } + old_table[i] = 0; + } + if (old_table != m_hash_table_0) + { + // + rtl_freeMemory (old_table); + } + } +} + +Entry * PageCache_Impl::lookup_Impl (Entry * entry, sal_uInt32 nOffset) +{ + register int lookups = 0; + while (entry != 0) + { + if (entry->m_nOffset == nOffset) + break; + + lookups += 1; + entry = entry->m_pNext; + } + if (lookups > 2) + { + sal_Size new_size = m_hash_size, ave = m_hash_entries >> m_hash_shift; + for (; ave > 4; new_size *= 2, ave /= 2) + continue; + if (new_size != m_hash_size) + rescale_Impl (new_size); + } + return entry; +} + +storeError PageCache_Impl::lookupPageAt_Impl ( + PageHolder & rxPage, + sal_uInt32 nOffset) +{ + int index = hash_index_Impl(nOffset); + Entry const * entry = lookup_Impl (m_hash_table[index], nOffset); + if (entry != 0) + { + // Existing entry. + rxPage = entry->m_xPage; + + // Update stats and leave. + m_nHit += 1; + return store_E_None; + } + + // Cache miss. Update stats and leave. + m_nMissed += 1; + return store_E_NotExists; +} + +storeError PageCache_Impl::insertPageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset) +{ + Entry * entry = EntryCache::get().create (rxPage, nOffset); + if (entry != 0) + { + // Insert new entry. + int index = hash_index_Impl(nOffset); + entry->m_pNext = m_hash_table[index], m_hash_table[index] = entry; + + // Update stats and leave. + m_hash_entries += 1; + return store_E_None; + } + return store_E_OutOfMemory; +} + +storeError PageCache_Impl::updatePageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset) +{ + int index = hash_index_Impl(nOffset); + Entry * entry = lookup_Impl (m_hash_table[index], nOffset); + if (entry != 0) + { + // Update existing entry. + entry->m_xPage = rxPage; + + // Update stats and leave. // m_nUpdHit += 1; + return store_E_None; + } + return insertPageAt_Impl (rxPage, nOffset); +} + +storeError PageCache_Impl::removePageAt_Impl ( + sal_uInt32 nOffset) +{ + Entry ** ppEntry = &(m_hash_table[hash_index_Impl(nOffset)]); + while (*ppEntry != 0) + { + if ((*ppEntry)->m_nOffset == nOffset) + { + // Existing entry. + Entry * entry = (*ppEntry); + + // Dequeue and destroy entry. + (*ppEntry) = entry->m_pNext, entry->m_pNext = 0; + EntryCache::get().destroy (entry); + + // Update stats and leave. + m_hash_entries -= 1; + return store_E_None; + } + ppEntry = &((*ppEntry)->m_pNext); + } + return store_E_NotExists; +} + +/*======================================================================== + * + * Old OStorePageCache implementation. + * + * (two-way association (sorted address array, LRU chain)). + * (external OStorePageData representation). + * + *======================================================================*/ + +/*======================================================================== + * + * PageCache factory implementation. + * + *======================================================================*/ +namespace store { + +storeError +PageCache_createInstance ( + rtl::Reference< store::PageCache > & rxCache, + sal_uInt16 nPageSize) +{ + rxCache = new PageCache_Impl (nPageSize); + if (!rxCache.is()) + return store_E_OutOfMemory; + + return store_E_None; +} + +} // namespace store diff --git a/store/source/storcach.hxx b/store/source/storcach.hxx new file mode 100644 index 000000000000..eb98bb786df5 --- /dev/null +++ b/store/source/storcach.hxx @@ -0,0 +1,115 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storcach.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORCACH_HXX +#define _STORE_STORCACH_HXX "$Revision: 1.6.8.2 $" + +#include "sal/types.h" +#include "rtl/ref.hxx" + +#include "store/types.h" +#include "storbase.hxx" + +namespace store +{ + +/*======================================================================== + * + * PageCache interface. + * + *======================================================================*/ + +class PageCache : public rtl::IReference +{ +public: + /** load. + */ + storeError lookupPageAt ( + PageHolder & rxPage, + sal_uInt32 nOffset); + + /** insert. + */ + storeError insertPageAt ( + PageHolder const & rxPage, + sal_uInt32 nOffset); + + /** update, or insert. + */ + storeError updatePageAt ( + PageHolder const & rxPage, + sal_uInt32 nOffset); + + /** remove (invalidate). + */ + storeError removePageAt ( + sal_uInt32 nOffset); + +private: + /** Implementation (abstract). + */ + virtual storeError lookupPageAt_Impl ( + PageHolder & rxPage, + sal_uInt32 nOffset) = 0; + + virtual storeError insertPageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset) = 0; + + virtual storeError updatePageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset) = 0; + + virtual storeError removePageAt_Impl ( + sal_uInt32 nOffset) = 0; +}; + +/*======================================================================== + * + * PageCache factory. + * + *======================================================================*/ + +storeError +PageCache_createInstance ( + rtl::Reference< store::PageCache > & rxCache, + sal_uInt16 nPageSize +); + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORCACH_HXX */ + diff --git a/store/source/stordata.cxx b/store/source/stordata.cxx new file mode 100644 index 000000000000..29350f8ebfdd --- /dev/null +++ b/store/source/stordata.cxx @@ -0,0 +1,1207 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: stordata.cxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "stordata.hxx" + +#include "sal/types.h" +#include "osl/diagnose.h" + +#include "store/types.h" +#include "storbase.hxx" +#include "storbios.hxx" + +using namespace store; + +/*======================================================================== + * + * OStoreDataPageObject implementation. + * + *======================================================================*/ +/* + * guard. + */ +storeError OStoreDataPageObject::guard (sal_uInt32 nAddr) +{ + return PageHolderObject< page >::guard (m_xPage, nAddr); +} + +/* + * verify. + */ +storeError OStoreDataPageObject::verify (sal_uInt32 nAddr) const +{ + return PageHolderObject< page >::verify (m_xPage, nAddr); +} + +/*======================================================================== + * + * OStoreIndirectionPageObject implementation. + * + *======================================================================*/ +/* + * store_truncate_Impl (single indirect page). + */ +static storeError store_truncate_Impl ( + sal_uInt32 nAddr, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + if (nAddr != STORE_PAGE_NULL) + { + // Load single indirect page. + OStoreIndirectionPageObject aSingle; + storeError eErrCode = rBIOS.loadObjectAt (aSingle, nAddr); + if (eErrCode == store_E_None) + { + // Truncate to 'nSingle' direct pages. + eErrCode = aSingle.truncate (nSingle, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + } + else + { + if (eErrCode != store_E_InvalidChecksum) + return eErrCode; + } + + // Check for complete truncation. + if (nSingle == 0) + { + // Free single indirect page. + OStorePageData aPageHead; + eErrCode = rBIOS.free (aPageHead, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + } + } + return store_E_None; +} + +/* + * store_truncate_Impl (double indirect page). + */ +static storeError store_truncate_Impl ( + sal_uInt32 nAddr, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + if (nAddr != STORE_PAGE_NULL) + { + // Load double indirect page. + OStoreIndirectionPageObject aDouble; + storeError eErrCode = rBIOS.loadObjectAt (aDouble, nAddr); + if (eErrCode == store_E_None) + { + // Truncate to 'nDouble', 'nSingle' pages. + eErrCode = aDouble.truncate (nDouble, nSingle, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + } + else + { + if (eErrCode != store_E_InvalidChecksum) + return eErrCode; + } + + // Check for complete truncation. + if ((nDouble + nSingle) == 0) + { + // Free double indirect page. + OStorePageData aPageHead; + eErrCode = rBIOS.free (aPageHead, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + } + } + return store_E_None; +} + +/* + * store_truncate_Impl (triple indirect page). + */ +static storeError store_truncate_Impl ( + sal_uInt32 nAddr, + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + if (nAddr != STORE_PAGE_NULL) + { + // Load triple indirect page. + OStoreIndirectionPageObject aTriple; + storeError eErrCode = rBIOS.loadObjectAt (aTriple, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate to 'nTriple', 'nDouble', 'nSingle' pages. + eErrCode = aTriple.truncate (nTriple, nDouble, nSingle, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if ((nTriple + nDouble + nSingle) == 0) + { + // Free triple indirect page. + OStorePageData aPageHead; + eErrCode = rBIOS.free (aPageHead, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + } + } + return store_E_None; +} + +/* + * loadOrCreate. + */ +storeError OStoreIndirectionPageObject::loadOrCreate ( + sal_uInt32 nAddr, + OStorePageBIOS & rBIOS) +{ + if (nAddr == STORE_PAGE_NULL) + { + storeError eErrCode = construct<page>(rBIOS.allocator()); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = rBIOS.allocate (*this); + if (eErrCode != store_E_None) + return eErrCode; + + // Save location pending at caller. + return store_E_Pending; + } + return rBIOS.loadObjectAt (*this, nAddr); +} + +/* + * guard. + */ +storeError OStoreIndirectionPageObject::guard (sal_uInt32 nAddr) +{ + return PageHolderObject< page >::guard (m_xPage, nAddr); +} + +/* + * verify. + */ +storeError OStoreIndirectionPageObject::verify (sal_uInt32 nAddr) const +{ + return PageHolderObject< page >::verify (m_xPage, nAddr); +} + +/* + * read (single indirect). + */ +storeError OStoreIndirectionPageObject::read ( + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page const & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!(nSingle < nLimit)) + return store_E_InvalidAccess; + + // Obtain data page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nSingle]); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + // Load data page and leave. + return rBIOS.loadObjectAt (rData, nAddr); +} + +/* + * read (double indirect). + */ +storeError OStoreIndirectionPageObject::read ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page const & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Check single indirect page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nDouble]); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + // Load single indirect page. + OStoreIndirectionPageObject aSingle; + storeError eErrCode = rBIOS.loadObjectAt (aSingle, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Read single indirect and leave. + return aSingle.read (nSingle, rData, rBIOS); +} + +/* + * read (triple indirect). + */ +storeError OStoreIndirectionPageObject::read ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page const & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Check double indirect page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nTriple]); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + // Load double indirect page. + OStoreIndirectionPageObject aDouble; + storeError eErrCode = rBIOS.loadObjectAt (aDouble, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Read double indirect and leave. + return aDouble.read (nDouble, nSingle, rData, rBIOS); +} + +/* + * write (single indirect). + */ +storeError OStoreIndirectionPageObject::write ( + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!(nSingle < nLimit)) + return store_E_InvalidAccess; + + // Obtain data page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nSingle]); + if (nAddr == STORE_PAGE_NULL) + { + // Allocate data page. + storeError eErrCode = rBIOS.allocate (rData); + if (eErrCode != store_E_None) + return eErrCode; + + // Store data page location. + rPage.m_pData[nSingle] = store::htonl(rData.location()); + + // Save this page. + return rBIOS.saveObjectAt (*this, location()); + } + else + { + // Save data page. + return rBIOS.saveObjectAt (rData, nAddr); + } +} + +/* + * write (double indirect). + */ +storeError OStoreIndirectionPageObject::write ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Load or create single indirect page. + OStoreIndirectionPageObject aSingle; + storeError eErrCode = aSingle.loadOrCreate (store::ntohl(rPage.m_pData[nDouble]), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + rPage.m_pData[nDouble] = store::htonl(aSingle.location()); + + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Write single indirect and leave. + return aSingle.write (nSingle, rData, rBIOS); +} + +/* + * write (triple indirect). + */ +storeError OStoreIndirectionPageObject::write ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Load or create double indirect page. + OStoreIndirectionPageObject aDouble; + storeError eErrCode = aDouble.loadOrCreate (store::ntohl(rPage.m_pData[nTriple]), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + rPage.m_pData[nTriple] = store::htonl(aDouble.location()); + + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Write double indirect and leave. + return aDouble.write (nDouble, nSingle, rData, rBIOS); +} + +/* + * truncate (single indirect). + */ +storeError OStoreIndirectionPageObject::truncate ( + sal_uInt16 nSingle, + OStorePageBIOS & rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!(nSingle < nLimit)) + return store_E_InvalidAccess; + + // Save PageDescriptor. + OStorePageDescriptor aDescr (rPage.m_aDescr); + aDescr.m_nAddr = store::ntohl(aDescr.m_nAddr); + aDescr.m_nSize = store::ntohs(aDescr.m_nSize); + + // Acquire Lock. + storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate. + for (sal_uInt16 i = nLimit; i > nSingle; i--) + { + // Obtain data page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[i - 1]); + if (nAddr != STORE_PAGE_NULL) + { + // Free data page. + OStorePageData aPageHead; + eErrCode = rBIOS.free (aPageHead, nAddr); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Clear pointer to data page. + rPage.m_pData[i - 1] = STORE_PAGE_NULL; + touch(); + } + } + + // Check for modified page. + if (dirty()) + { + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + { + // Must not happen. + OSL_TRACE("OStoreIndirectionPageObject::truncate(): save failed"); + + // Release Lock and Leave. + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + } + + // Release Lock and Leave. + return rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); +} + +/* + * truncate (double indirect). + */ +storeError OStoreIndirectionPageObject::truncate ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Save PageDescriptor. + OStorePageDescriptor aDescr (rPage.m_aDescr); + aDescr.m_nAddr = store::ntohl(aDescr.m_nAddr); + aDescr.m_nSize = store::ntohs(aDescr.m_nSize); + + // Acquire Lock. + storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate. + for (sal_uInt16 i = nLimit; i > nDouble + 1; i--) + { + // Truncate single indirect page to zero direct pages. + eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[i - 1]), 0, rBIOS); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Clear pointer to single indirect page. + rPage.m_pData[i - 1] = STORE_PAGE_NULL; + touch(); + } + + // Truncate last single indirect page to 'nSingle' direct pages. + eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[nDouble]), nSingle, rBIOS); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Check for complete truncation. + if (nSingle == 0) + { + // Clear pointer to last single indirect page. + rPage.m_pData[nDouble] = STORE_PAGE_NULL; + touch(); + } + + // Check for modified page. + if (dirty()) + { + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + { + // Must not happen. + OSL_TRACE("OStoreIndirectionPageObject::truncate(): save failed"); + + // Release Lock and Leave. + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + } + + // Release Lock and Leave. + return rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); +} + +/* + * truncate (triple indirect). + */ +storeError OStoreIndirectionPageObject::truncate ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Save PageDescriptor. + OStorePageDescriptor aDescr (rPage.m_aDescr); + aDescr.m_nAddr = store::ntohl(aDescr.m_nAddr); + aDescr.m_nSize = store::ntohs(aDescr.m_nSize); + + // Acquire Lock. + storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate. + for (sal_uInt16 i = nLimit; i > nTriple + 1; i--) + { + // Truncate double indirect page to zero single indirect pages. + eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[i - 1]), 0, 0, rBIOS); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Clear pointer to double indirect page. + rPage.m_pData[i - 1] = STORE_PAGE_NULL; + touch(); + } + + // Truncate last double indirect page to 'nDouble', 'nSingle' pages. + eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[nTriple]), nDouble, nSingle, rBIOS); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Check for complete truncation. + if ((nDouble + nSingle) == 0) + { + // Clear pointer to last double indirect page. + rPage.m_pData[nTriple] = STORE_PAGE_NULL; + touch(); + } + + // Check for modified page. + if (dirty()) + { + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + { + // Must not happen. + OSL_TRACE("OStoreIndirectionPageObject::truncate(): save failed"); + + // Release Lock and Leave. + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + } + + // Release Lock and Leave. + return rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); +} + +/*======================================================================== + * + * OStoreDirectoryPageObject implementation. + * + *======================================================================*/ +/* + * guard. + */ +storeError OStoreDirectoryPageObject::guard (sal_uInt32 nAddr) +{ + return PageHolderObject< page >::guard (m_xPage, nAddr); +} + +/* + * verify. + */ +storeError OStoreDirectoryPageObject::verify (sal_uInt32 nAddr) const +{ + return PageHolderObject< page >::verify (m_xPage, nAddr); + // OLD: m_rPage.verifyVersion (STORE_MAGIC_DIRECTORYPAGE); +} + +/* + * scope (external data page; private). + */ +OStoreDirectoryPageData::ChunkScope +OStoreDirectoryPageObject::scope ( + sal_uInt32 nPage, + page::DataBlock::LinkDescriptor &rDescr) const +{ + page const & rPage = PAGE(); + OStoreDirectoryDataBlock const & rDataBlock = rPage.m_aDataBlock; + + sal_uInt32 index0, index1, index2, index3; + + // direct. + sal_uInt32 nCount = rDataBlock.directCount(); + sal_uInt32 nLimit = nCount; + if (nPage < nLimit) + { + // Page to index reduction. + index0 = nPage; + + // Setup LinkDescriptor indices. + rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff); + + // Done. + return page::SCOPE_DIRECT; + } + nPage -= nLimit; + + // single indirect. + sal_uInt32 const nCapacity = indirect::capacityCount(rPage.m_aDescr); + nCount = rDataBlock.singleCount(); + nLimit = nCount * nCapacity; + if (nPage < nLimit) + { + // Page to index reduction. + sal_uInt32 n = nPage; + + // Reduce to single indirect i(1), direct n = i(0). + index1 = n / nCapacity; + index0 = n % nCapacity; + + // Verify reduction. + n = index1 * nCapacity + index0; + OSL_POSTCOND(n == nPage, "wrong math on indirect indices"); + if (n != nPage) + return page::SCOPE_UNKNOWN; + + // Setup LinkDescriptor indices. + rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff); + rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff); + + // Done. + return page::SCOPE_SINGLE; + } + nPage -= nLimit; + + // double indirect. + nCount = rDataBlock.doubleCount(); + nLimit = nCount * nCapacity * nCapacity; + if (nPage < nLimit) + { + // Page to index reduction. + sal_uInt32 n = nPage; + + // Reduce to double indirect i(2), single indirect n = i(0). + index2 = n / (nCapacity * nCapacity); + n = n % (nCapacity * nCapacity); + + // Reduce to single indirect i(1), direct n = i(0). + index1 = n / nCapacity; + index0 = n % nCapacity; + + // Verify reduction. + n = index2 * nCapacity * nCapacity + + index1 * nCapacity + index0; + OSL_POSTCOND(n == nPage, "wrong math on double indirect indices"); + if (n != nPage) + return page::SCOPE_UNKNOWN; + + // Setup LinkDescriptor indices. + rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff); + rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff); + rDescr.m_nIndex2 = (sal_uInt16)(index2 & 0xffff); + + // Done. + return page::SCOPE_DOUBLE; + } + nPage -= nLimit; + + // triple indirect. + nCount = rDataBlock.tripleCount(); + nLimit = nCount * nCapacity * nCapacity * nCapacity; + if (nPage < nLimit) + { + // Page to index reduction. + sal_uInt32 n = nPage; + + // Reduce to triple indirect i(3), double indirect n. + index3 = n / (nCapacity * nCapacity * nCapacity); + n = n % (nCapacity * nCapacity * nCapacity); + + // Reduce to double indirect i(2), single indirect n. + index2 = n / (nCapacity * nCapacity); + n = n % (nCapacity * nCapacity); + + // Reduce to single indirect i(1), direct n = i(0). + index1 = n / nCapacity; + index0 = n % nCapacity; + + // Verify reduction. + n = index3 * nCapacity * nCapacity * nCapacity + + index2 * nCapacity * nCapacity + + index1 * nCapacity + index0; + OSL_POSTCOND(n == nPage, "wrong math on triple indirect indices"); + if (n != nPage) + return page::SCOPE_UNKNOWN; + + // Setup LinkDescriptor indices. + rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff); + rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff); + rDescr.m_nIndex2 = (sal_uInt16)(index2 & 0xffff); + rDescr.m_nIndex3 = (sal_uInt16)(index3 & 0xffff); + + // Done. + return page::SCOPE_TRIPLE; + } + + // Unreachable (more than triple indirect). + return page::SCOPE_UNREACHABLE; +} + +#if 0 /* NYI */ +/* + * chunk (external data page). + */ +inode::ChunkDescriptor OStoreDirectoryPageObject::chunk (sal_uInt32 nOffset) +{ + // @@@ INSUFFICIENT: NEED SCOPE AS WELL @@@ + sal_uInt32 nCapacity = m_rPage.capacity(); + if (nOffset < nCapacity) + // Internal scope (inode page). + return inode::ChunkDescriptor (nOffset, nCapacity); + else + // External scope (data page). + return inode::ChunkDescriptor (nOffset - nCapacity, data::capacity(m_rPage.m_aDescr)); + + inode::ChunkScope eScope = m_rPage.scope(nOffset); + if (eScope == inode::SCOPE_INTERNAL) + // Inode page (internal scope). + return inode::ChunkDescriptor (nOffset, m_rPage.capacity()); + else + // Data page (external scope). + return inode::ChunkDescriptor (nOffset - m_rPage.capacity(), data::capacity(m_rPage.m_aDescr)); +} +#endif /* NYI */ + +/* + * read (external data page). + */ +storeError OStoreDirectoryPageObject::read ( + sal_uInt32 nPage, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + // Determine scope and link indices. + page::DataBlock::LinkDescriptor aLink; + page::ChunkScope eScope = scope (nPage, aLink); + + storeError eErrCode = store_E_None; + if (eScope == page::SCOPE_DIRECT) + { + sal_uInt32 const nAddr = directLink (aLink.m_nIndex0); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + eErrCode = rBIOS.loadObjectAt (rData, nAddr); + } + else if (eScope == page::SCOPE_SINGLE) + { + sal_uInt32 const nAddr = singleLink (aLink.m_nIndex1); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + OStoreIndirectionPageObject aSingle; + eErrCode = rBIOS.loadObjectAt (aSingle, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = aSingle.read (aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_DOUBLE) + { + sal_uInt32 const nAddr = doubleLink (aLink.m_nIndex2); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + OStoreIndirectionPageObject aDouble; + eErrCode = rBIOS.loadObjectAt (aDouble, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = aDouble.read (aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_TRIPLE) + { + sal_uInt32 const nAddr = tripleLink (aLink.m_nIndex3); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + OStoreIndirectionPageObject aTriple; + eErrCode = rBIOS.loadObjectAt (aTriple, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = aTriple.read (aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_UNREACHABLE) + { + // Out of scope. + eErrCode = store_E_CantSeek; + } + else + { + // Unknown scope. + OSL_TRACE("OStoreDirectoryPageObject::get(): scope failed"); + eErrCode = store_E_Unknown; + } + + // Leave. + return eErrCode; +} + +/* + * write (external data page). + */ +storeError OStoreDirectoryPageObject::write ( + sal_uInt32 nPage, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + // Determine scope and link indices. + page::DataBlock::LinkDescriptor aLink; + page::ChunkScope eScope = scope (nPage, aLink); + + storeError eErrCode = store_E_None; + if (eScope == page::SCOPE_DIRECT) + { + sal_uInt32 const nAddr = directLink (aLink.m_nIndex0); + if (nAddr == STORE_PAGE_NULL) + { + // Allocate data page. + eErrCode = rBIOS.allocate (rData); + if (eErrCode != store_E_None) + return eErrCode; + + // Store data page location. + directLink (aLink.m_nIndex0, rData.location()); + } + else + { + // Save data page. + eErrCode = rBIOS.saveObjectAt (rData, nAddr); + } + } + else if (eScope == page::SCOPE_SINGLE) + { + OStoreIndirectionPageObject aSingle; + eErrCode = aSingle.loadOrCreate (singleLink (aLink.m_nIndex1), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + singleLink (aLink.m_nIndex1, aSingle.location()); + } + + eErrCode = aSingle.write (aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_DOUBLE) + { + OStoreIndirectionPageObject aDouble; + eErrCode = aDouble.loadOrCreate (doubleLink (aLink.m_nIndex2), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + doubleLink (aLink.m_nIndex2, aDouble.location()); + } + + eErrCode = aDouble.write (aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_TRIPLE) + { + OStoreIndirectionPageObject aTriple; + eErrCode = aTriple.loadOrCreate (tripleLink (aLink.m_nIndex3), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + tripleLink (aLink.m_nIndex3, aTriple.location()); + } + + eErrCode = aTriple.write (aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_UNREACHABLE) + { + // Out of scope. + eErrCode = store_E_CantSeek; + } + else + { + // Unknown scope. + OSL_TRACE("OStoreDirectoryPageObject::put(): scope failed"); + eErrCode = store_E_Unknown; + } + + // Leave. + return eErrCode; +} + +/* + * truncate (external data page). + */ +storeError OStoreDirectoryPageObject::truncate ( + sal_uInt32 nPage, + OStorePageBIOS &rBIOS) +{ + // Determine scope and link indices. + page::DataBlock::LinkDescriptor aLink; + page::ChunkScope eScope = scope (nPage, aLink); + + storeError eErrCode = store_E_None; + if (eScope == page::SCOPE_DIRECT) + { + // Truncate all triple indirect pages. + eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate all double indirect pages. + eErrCode = truncate (page::SCOPE_DOUBLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate all single indirect pages. + eErrCode = truncate (page::SCOPE_SINGLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate direct pages, including 'aLink.m_nIndex0'. + eErrCode = truncate (eScope, aLink.m_nIndex0, rBIOS); + } + else if (eScope == page::SCOPE_SINGLE) + { + // Truncate all triple indirect pages. + eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate all double indirect pages. + eErrCode = truncate (page::SCOPE_DOUBLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate single indirect pages, downto 'aLink.m_nIndex1'. + eErrCode = truncate (eScope, aLink.m_nIndex1 + 1, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate last single indirect page to ... pages. + eErrCode = store_truncate_Impl (singleLink (aLink.m_nIndex1), aLink.m_nIndex0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if (aLink.m_nIndex0 == 0) + { + // Clear pointer to last single indirect page. + singleLink (aLink.m_nIndex1, STORE_PAGE_NULL); + } + } + else if (eScope == page::SCOPE_DOUBLE) + { + // Truncate all triple indirect pages. + eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate double indirect pages, downto 'aLink.m_nIndex2'. + eErrCode = truncate (eScope, aLink.m_nIndex2 + 1, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate last double indirect page to ... pages. + eErrCode = store_truncate_Impl ( + doubleLink (aLink.m_nIndex2), aLink.m_nIndex1, aLink.m_nIndex0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if ((aLink.m_nIndex1 + aLink.m_nIndex0) == 0) + { + // Clear pointer to last double indirect page. + doubleLink (aLink.m_nIndex2, STORE_PAGE_NULL); + } + } + else if (eScope == page::SCOPE_TRIPLE) + { + // Truncate triple indirect pages, downto 'aLink.m_nIndex3'. + eErrCode = truncate (eScope, aLink.m_nIndex3 + 1, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate last triple indirect page to ... pages. + eErrCode = store_truncate_Impl ( + tripleLink (aLink.m_nIndex3), aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if ((aLink.m_nIndex2 + aLink.m_nIndex1 + aLink.m_nIndex0) == 0) + { + // Clear pointer to last triple indirect page. + tripleLink (aLink.m_nIndex3, STORE_PAGE_NULL); + } + } + else if (eScope == page::SCOPE_UNREACHABLE) + { + // Out of scope. + eErrCode = store_E_CantSeek; + } + else + { + // Unknown scope. + OSL_TRACE("OStoreDirectoryPageObject::put(): scope failed"); + eErrCode = store_E_Unknown; + } + + // Leave. + return eErrCode; +} + +/* + * truncate (external data page scope; private). + */ +storeError OStoreDirectoryPageObject::truncate ( + page::ChunkScope eScope, + sal_uInt16 nRemain, + OStorePageBIOS &rBIOS) +{ + OStoreDirectoryDataBlock const & rDataBlock = PAGE().m_aDataBlock; + + // Enter. + storeError eErrCode = store_E_None; + if (eScope == page::SCOPE_DIRECT) + { + // Truncate direct data pages. + sal_uInt16 i, n = rDataBlock.directCount(); + for (i = n; i > nRemain; i--) + { + // Obtain data page location. + sal_uInt32 nAddr = directLink (i - 1); + if (nAddr == STORE_PAGE_NULL) continue; + + // Free data page. + OStoreDataPageData aData; + eErrCode = rBIOS.free (aData, nAddr); + if (eErrCode != store_E_None) + break; + + // Clear pointer to data page. + directLink (i - 1, STORE_PAGE_NULL); + } + + // Done. + return eErrCode; + } + + if (eScope == page::SCOPE_SINGLE) + { + // Truncate single indirect pages. + sal_uInt16 i, n = rDataBlock.singleCount(); + for (i = n; i > nRemain; i--) + { + // Truncate single indirect page to zero data pages. + eErrCode = store_truncate_Impl (singleLink (i - 1), 0, rBIOS); + if (eErrCode != store_E_None) + break; + + // Clear pointer to single indirect page. + singleLink (i - 1, STORE_PAGE_NULL); + } + + // Done. + return eErrCode; + } + + if (eScope == page::SCOPE_DOUBLE) + { + // Truncate double indirect pages. + sal_uInt16 i, n = rDataBlock.doubleCount(); + for (i = n; i > nRemain; i--) + { + // Truncate double indirect page to zero single indirect pages. + eErrCode = store_truncate_Impl (doubleLink (i - 1), 0, 0, rBIOS); + if (eErrCode != store_E_None) + break; + + // Clear pointer to double indirect page. + doubleLink (i - 1, STORE_PAGE_NULL); + } + + // Done. + return eErrCode; + } + + if (eScope == page::SCOPE_TRIPLE) + { + // Truncate triple indirect pages. + sal_uInt16 i, n = rDataBlock.tripleCount(); + for (i = n; i > nRemain; i--) + { + // Truncate to zero double indirect pages. + eErrCode = store_truncate_Impl (tripleLink (i - 1), 0, 0, 0, rBIOS); + if (eErrCode != store_E_None) + break; + + // Clear pointer to triple indirect page. + tripleLink (i - 1, STORE_PAGE_NULL); + } + + // Done. + return eErrCode; + } + + // Invalid scope. + return store_E_InvalidAccess; +} diff --git a/store/source/stordata.hxx b/store/source/stordata.hxx new file mode 100644 index 000000000000..4610bac425fd --- /dev/null +++ b/store/source/stordata.hxx @@ -0,0 +1,873 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: stordata.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORDATA_HXX_ +#define _STORE_STORDATA_HXX_ "$Revision: 1.6.8.2 $" + +#include "sal/types.h" +#include "sal/macros.h" + +#include "store/types.h" +#include "storbase.hxx" + +namespace store +{ + +/*======================================================================== + * + * OStoreDataPageData. + * + *======================================================================*/ +#define STORE_MAGIC_DATAPAGE sal_uInt32(0x94190310) + +struct OStoreDataPageData : public store::OStorePageData +{ + typedef OStorePageData base; + typedef OStoreDataPageData self; + + typedef OStorePageDescriptor D; + + /** Representation. + */ + sal_uInt8 m_pData[1]; + + /** type. + */ + static const sal_uInt32 theTypeId = STORE_MAGIC_DATAPAGE; + + /** size. + */ + static const size_t theSize = 0; + static const sal_uInt16 thePageSize = base::theSize + self::theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= self::thePageSize); + + /** capacity. + */ + static sal_uInt16 capacity (const D& rDescr) // @see inode::ChunkDescriptor + { + return (store::ntohs(rDescr.m_nSize) - self::thePageSize); + } + sal_uInt16 capacity() const + { + return self::capacity (base::m_aDescr); + } + + /** usage. + */ + sal_uInt16 usage() const + { + return (store::ntohs(base::m_aDescr.m_nUsed) - self::thePageSize); + } + + /** Construction. + */ + explicit OStoreDataPageData (sal_uInt16 nPageSize = self::thePageSize) + : base (nPageSize) + { + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); + if (capacity()) memset (m_pData, 0, capacity()); + } + + /** guard (external representation). + */ + void guard() {} + + /** verify (external representation). + */ + storeError verify() const { return store_E_None; } +}; + +/*======================================================================== + * + * OStoreDataPageObject. + * + *======================================================================*/ +class OStoreDataPageObject : public store::OStorePageObject +{ + typedef OStorePageObject base; + typedef OStoreDataPageData page; + +public: + /** Construction. + */ + explicit OStoreDataPageObject (PageHolder const & rxPage = PageHolder()) + : OStorePageObject (rxPage) + {} + + /** External representation. + */ + virtual storeError guard (sal_uInt32 nAddr); + virtual storeError verify (sal_uInt32 nAddr) const; +}; + +/*======================================================================== + * + * OStoreIndirectionPageData. + * + *======================================================================*/ +#define STORE_MAGIC_INDIRECTPAGE sal_uInt32(0x89191107) + +struct OStoreIndirectionPageData : public store::OStorePageData +{ + typedef OStorePageData base; + typedef OStoreIndirectionPageData self; + + typedef OStorePageGuard G; + typedef OStorePageDescriptor D; + + /** Representation. + */ + G m_aGuard; + sal_uInt32 m_pData[1]; + + /** type. + */ + static const sal_uInt32 theTypeId = STORE_MAGIC_INDIRECTPAGE; + + /** size. + */ + static const size_t theSize = sizeof(G); + static const sal_uInt16 thePageSize = base::theSize + self::theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= self::thePageSize); + + /** capacity. + */ + static sal_uInt16 capacity (const D& rDescr) + { + return (store::ntohs(rDescr.m_nSize) - self::thePageSize); + } + sal_uInt16 capacity() const + { + return self::capacity (base::m_aDescr); + } + + /** capacityCount. + */ + static sal_uInt16 capacityCount (const D& rDescr) // @see DirectoryPageObject::scope() + { + return sal_uInt16(capacity(rDescr) / sizeof(sal_uInt32)); + } + sal_uInt16 capacityCount() const + { + return sal_uInt16(capacity() / sizeof(sal_uInt32)); + } + + /** Construction. + */ + explicit OStoreIndirectionPageData (sal_uInt16 nPageSize) + : base (nPageSize) + { + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); + self::m_aGuard.m_nMagic = store::htonl(0); + memset (m_pData, STORE_PAGE_NULL, capacity()); + } + + /** guard (external representation). + */ + void guard() + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, m_pData, capacity()); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, m_pData, capacity()); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } +}; + +/*======================================================================== + * + * OStoreIndirectionPageObject. + * + *======================================================================*/ +class OStoreIndirectionPageObject : public store::OStorePageObject +{ + typedef OStorePageObject base; + typedef OStoreIndirectionPageData page; + +public: + /** Construction. + */ + explicit OStoreIndirectionPageObject (PageHolder const & rxPage = PageHolder()) + : OStorePageObject (rxPage) + {} + + /** External representation. + */ + storeError loadOrCreate ( + sal_uInt32 nAddr, + OStorePageBIOS & rBIOS); + + virtual storeError guard (sal_uInt32 nAddr); + virtual storeError verify (sal_uInt32 nAddr) const; + + /** read (indirect data page). + */ + storeError read ( + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + storeError read ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + storeError read ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + /** write (indirect data page). + */ + storeError write ( + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + storeError write ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + storeError write ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + /** truncate (indirect data page). + */ + storeError truncate ( + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS); + + storeError truncate ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS); + + storeError truncate ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS); +}; + +/*======================================================================== + * + * OStorePageNameBlock. + * + *======================================================================*/ +struct OStorePageNameBlock +{ + typedef OStorePageGuard G; + typedef OStorePageKey K; + + /** Representation. + */ + G m_aGuard; + K m_aKey; + sal_uInt32 m_nAttrib; + sal_Char m_pData[STORE_MAXIMUM_NAMESIZE]; + + /** size. + */ + static const size_t theSize = sizeof(G) + sizeof(K) + sizeof(sal_uInt32) + sizeof(sal_Char[STORE_MAXIMUM_NAMESIZE]); + + /** initialize. + */ + void initialize (void) + { + m_aGuard = G(); + m_aKey = K(); + m_nAttrib = 0; + memset (m_pData, 0, sizeof(m_pData)); + } + + /** Construction. + */ + OStorePageNameBlock (void) + : m_aGuard(), m_aKey(), m_nAttrib (0) + { + memset (m_pData, 0, sizeof(m_pData)); + } + + /** guard (external representation). + */ + void guard() + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aKey, theSize - sizeof(G)); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aKey, theSize - sizeof(G)); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } +}; + +/*======================================================================== + * + * OStoreDirectoryDataBlock. + * + *======================================================================*/ +#define STORE_LIMIT_DATAPAGE_DIRECT 16 +#define STORE_LIMIT_DATAPAGE_SINGLE 8 +#define STORE_LIMIT_DATAPAGE_DOUBLE 1 +#define STORE_LIMIT_DATAPAGE_TRIPLE 1 + +struct OStoreDirectoryDataBlock +{ + typedef OStorePageGuard G; + + /** LinkDescriptor. + */ + struct LinkDescriptor + { + /** Representation. + */ + sal_uInt16 m_nIndex0; + sal_uInt16 m_nIndex1; + sal_uInt16 m_nIndex2; + sal_uInt16 m_nIndex3; + + /** Construction. + */ + LinkDescriptor (void) + : m_nIndex0 ((sal_uInt16)(~0)), + m_nIndex1 ((sal_uInt16)(~0)), + m_nIndex2 ((sal_uInt16)(~0)), + m_nIndex3 ((sal_uInt16)(~0)) + {} + }; + + /** LinkTable. + */ + struct LinkTable + { + /** Representation. + */ + sal_uInt32 m_pDirect[STORE_LIMIT_DATAPAGE_DIRECT]; + sal_uInt32 m_pSingle[STORE_LIMIT_DATAPAGE_SINGLE]; + sal_uInt32 m_pDouble[STORE_LIMIT_DATAPAGE_DOUBLE]; + sal_uInt32 m_pTriple[STORE_LIMIT_DATAPAGE_TRIPLE]; + + /** initialize. + */ + void initialize (void) + { + memset(m_pDirect, STORE_PAGE_NULL, sizeof(m_pDirect)); + memset(m_pSingle, STORE_PAGE_NULL, sizeof(m_pSingle)); + memset(m_pDouble, STORE_PAGE_NULL, sizeof(m_pDouble)); + memset(m_pTriple, STORE_PAGE_NULL, sizeof(m_pTriple)); + } + + /** Construction. + */ + LinkTable (void) + { + initialize(); + } + }; + + /** Representation. + */ + G m_aGuard; + LinkTable m_aTable; + sal_uInt32 m_nDataLen; + + /** size. + */ + static const size_t theSize = sizeof(G) + sizeof(LinkTable) + sizeof(sal_uInt32); + + /** initialize. + */ + void initialize (void) + { + m_aGuard = G(); + m_aTable.initialize(); + m_nDataLen = 0; + } + + /** Construction. + */ + OStoreDirectoryDataBlock (void) + : m_aGuard(), m_aTable(), m_nDataLen (0) + {} + + /** guard (external representation). + */ + void guard() + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aTable, theSize - sizeof(G)); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aTable, theSize - sizeof(G)); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } + + /** direct. + */ + static sal_uInt16 directCount (void) + { + return ((sal_uInt16)(STORE_LIMIT_DATAPAGE_DIRECT)); + } + sal_uInt32 directLink (sal_uInt16 nIndex) const + { + if (nIndex < directCount()) + return store::ntohl(m_aTable.m_pDirect[nIndex]); + else + return STORE_PAGE_NULL; + } + void directLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + if (nIndex < directCount()) + m_aTable.m_pDirect[nIndex] = store::htonl(nAddr); + } + + /** single. + */ + static sal_uInt16 singleCount (void) + { + return ((sal_uInt16)(STORE_LIMIT_DATAPAGE_SINGLE)); + } + sal_uInt32 singleLink (sal_uInt16 nIndex) const + { + if (nIndex < singleCount()) + return store::ntohl(m_aTable.m_pSingle[nIndex]); + else + return STORE_PAGE_NULL; + } + void singleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + if (nIndex < singleCount()) + m_aTable.m_pSingle[nIndex] = store::htonl(nAddr); + } + + /** double. + */ + static sal_uInt16 doubleCount (void) + { + return ((sal_uInt16)(STORE_LIMIT_DATAPAGE_DOUBLE)); + } + sal_uInt32 doubleLink (sal_uInt16 nIndex) const + { + if (nIndex < doubleCount()) + return store::ntohl(m_aTable.m_pDouble[nIndex]); + else + return STORE_PAGE_NULL; + } + void doubleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + if (nIndex < doubleCount()) + m_aTable.m_pDouble[nIndex] = store::htonl(nAddr); + } + + /** triple. + */ + static sal_uInt16 tripleCount (void) + { + return ((sal_uInt16)(STORE_LIMIT_DATAPAGE_TRIPLE)); + } + sal_uInt32 tripleLink (sal_uInt16 nIndex) const + { + if (nIndex < tripleCount()) + return store::ntohl(m_aTable.m_pTriple[nIndex]); + else + return STORE_PAGE_NULL; + } + void tripleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + if (nIndex < tripleCount()) + m_aTable.m_pTriple[nIndex] = store::htonl(nAddr); + } +}; + +/*======================================================================== + * + * OStoreDirectoryPageData. + * + *======================================================================*/ +#define STORE_MAGIC_DIRECTORYPAGE sal_uInt32(0x62190120) + +struct OStoreDirectoryPageData : public store::OStorePageData +{ + typedef OStorePageData base; + typedef OStoreDirectoryPageData self; + + typedef OStorePageDescriptor D; + typedef OStorePageNameBlock NameBlock; + typedef OStoreDirectoryDataBlock DataBlock; + + /** Representation. + */ + NameBlock m_aNameBlock; + DataBlock m_aDataBlock; + sal_uInt8 m_pData[1]; + + /** type. + */ + static const sal_uInt32 theTypeId = STORE_MAGIC_DIRECTORYPAGE; + + /** size. + */ + static const size_t theSize = NameBlock::theSize + DataBlock::theSize; + static const sal_uInt16 thePageSize = base::theSize + self::theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= self::thePageSize); + + /** capacity. + */ + sal_uInt16 capacity() const + { + return (store::ntohs(base::m_aDescr.m_nSize) - self::thePageSize); + } + + /** usage. + */ + sal_uInt16 usage() const + { + return (store::ntohs(base::m_aDescr.m_nUsed) - self::thePageSize); + } + + /** initialize. + */ + void initialize (void) + { + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); + + m_aNameBlock.initialize(); + m_aDataBlock.initialize(); + + memset (m_pData, 0, capacity()); + } + + /** Construction. + */ + explicit OStoreDirectoryPageData (sal_uInt16 nPageSize) + : base (nPageSize), m_aNameBlock(), m_aDataBlock() + { + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); + memset (m_pData, 0, capacity()); + } + + /** guard (external representation). + */ + void guard() + { + m_aNameBlock.guard(); + m_aDataBlock.guard(); + } + + /** verify (external representation). + */ + storeError verify() const + { + storeError eErrCode = m_aNameBlock.verify(); + if (eErrCode == store_E_None) + eErrCode = m_aDataBlock.verify(); + return eErrCode; + } + + /** ChunkDescriptor. + */ + struct ChunkDescriptor + { + /** Representation. + */ + sal_uInt32 m_nPage; + sal_uInt16 m_nOffset; + sal_uInt16 m_nLength; + + /** Construction. + */ + ChunkDescriptor (sal_uInt32 nPosition, sal_uInt16 nCapacity) + { + m_nPage = nPosition / nCapacity; + m_nOffset = (sal_uInt16)((nPosition % nCapacity) & 0xffff); + m_nLength = nCapacity - m_nOffset; + } + }; + + /** ChunkScope. + */ + enum ChunkScope + { + SCOPE_INTERNAL, + SCOPE_EXTERNAL, + SCOPE_DIRECT, + SCOPE_SINGLE, + SCOPE_DOUBLE, + SCOPE_TRIPLE, + SCOPE_UNREACHABLE, + SCOPE_UNKNOWN + }; + + /** scope (internal). + */ + ChunkScope scope (sal_uInt32 nPosition) const + { + sal_uInt32 nCapacity = capacity(); + if (nPosition < nCapacity) + return SCOPE_INTERNAL; + else + return SCOPE_EXTERNAL; + } +}; + +/*======================================================================== + * + * OStoreDirectoryPageObject. + * + *======================================================================*/ +class OStoreDirectoryPageObject : public store::OStorePageObject +{ + typedef OStorePageObject base; + typedef OStoreDirectoryPageData page; + typedef OStoreIndirectionPageData indirect; + + typedef OStorePageDescriptor D; + +public: + /** Construction. + */ + explicit OStoreDirectoryPageObject (PageHolder const & rxPage = PageHolder()) + : OStorePageObject (rxPage) + {} + + /** External representation. + */ + virtual storeError guard (sal_uInt32 nAddr); + virtual storeError verify (sal_uInt32 nAddr) const; + + /** attrib. + */ + sal_uInt32 attrib (void) const + { + return store::ntohl(PAGE().m_aNameBlock.m_nAttrib); + } + void attrib (sal_uInt32 nAttrib) + { + PAGE().m_aNameBlock.m_nAttrib = store::htonl(nAttrib); + touch(); + } + + /** key. + */ + OStorePageKey key (void) const + { + return PAGE().m_aNameBlock.m_aKey; + } + void key (OStorePageKey const & rKey) + { + PAGE().m_aNameBlock.m_aKey = rKey; + touch(); + } + + /** path. + */ + sal_uInt32 path (void) const + { + page const & rPage = PAGE(); + const sal_Char * pszName = rPage.m_aNameBlock.m_pData; + sal_uInt32 nPath = store::ntohl(rPage.m_aNameBlock.m_aKey.m_nHigh); + return rtl_crc32 (nPath, pszName, rtl_str_getLength(pszName)); + } + + sal_Size getName (sal_Char * pBuffer, sal_Size nBufsiz) const + { + sal_Char const * pszName = PAGE().m_aNameBlock.m_pData; + sal_Size nLength = rtl_str_getLength(pszName); + memcpy (pBuffer, pszName, SAL_MIN(nLength, nBufsiz)); + return nLength; + } + + /** dataLength. + */ + sal_uInt32 dataLength (void) const + { + return store::ntohl(PAGE().m_aDataBlock.m_nDataLen); + } + void dataLength (sal_uInt32 nLength) + { + PAGE().m_aDataBlock.m_nDataLen = store::htonl(nLength); + touch(); + } + + /** direct. + */ + sal_uInt32 directLink (sal_uInt16 nIndex) const + { + return PAGE().m_aDataBlock.directLink (nIndex); + } + void directLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + PAGE().m_aDataBlock.directLink (nIndex, nAddr); + touch(); + } + + /** single indirect. + */ + sal_uInt32 singleLink (sal_uInt16 nIndex) const + { + return PAGE().m_aDataBlock.singleLink (nIndex); + } + void singleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + PAGE().m_aDataBlock.singleLink (nIndex, nAddr); + touch(); + } + + /** double indirect. + */ + sal_uInt32 doubleLink (sal_uInt16 nIndex) const + { + return PAGE().m_aDataBlock.doubleLink (nIndex); + } + void doubleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + PAGE().m_aDataBlock.doubleLink (nIndex, nAddr); + touch(); + } + + /** triple indirect. + */ + sal_uInt32 tripleLink (sal_uInt16 nIndex) const + { + return PAGE().m_aDataBlock.tripleLink (nIndex); + } + void tripleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + PAGE().m_aDataBlock.tripleLink (nIndex, nAddr); + touch(); + } + + /** read (external data page). + */ + storeError read ( + sal_uInt32 nPage, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + /** write (external data page). + */ + storeError write ( + sal_uInt32 nPage, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + /** truncate (external data page). + */ + storeError truncate ( + sal_uInt32 nPage, + OStorePageBIOS &rBIOS); + +private: + /** Representation. + */ + page & PAGE() + { + page * pImpl = static_cast<page*>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "OStoreDirectoryPageObject::PAGE(): Null pointer"); + return (*pImpl); + } + page const & PAGE() const + { + page const * pImpl = static_cast<page const *>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "OStoreDirectoryPageObject::PAGE(): Null pointer"); + return (*pImpl); + } + + /** scope (external data page; private). + */ + page::ChunkScope scope ( + sal_uInt32 nPage, + page::DataBlock::LinkDescriptor &rDescr) const; + + /** truncate (external data page scope; private). + */ + storeError truncate ( + page::ChunkScope eScope, + sal_uInt16 nRemain, + OStorePageBIOS &rBIOS); +}; + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORDATA_HXX_ */ + diff --git a/store/source/stordir.cxx b/store/source/stordir.cxx new file mode 100644 index 000000000000..0269e9cb51f1 --- /dev/null +++ b/store/source/stordir.cxx @@ -0,0 +1,249 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: stordir.cxx,v $ + * + * $Revision: 1.1.2.2 $ + * + * last change: $Author: mhu $ $Date: 2008/10/17 16:30:17 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "stordir.hxx" + +#ifndef _SAL_TYPES_H_ +#include <sal/types.h> +#endif + +#ifndef _RTL_TEXTCVT_H_ +#include <rtl/textcvt.h> +#endif +#ifndef _RTL_REF_HXX_ +#include <rtl/ref.hxx> +#endif + +#ifndef _OSL_MUTEX_HXX_ +#include <osl/mutex.hxx> +#endif + +#ifndef _STORE_TYPES_H_ +#include "store/types.h" +#endif +#ifndef _STORE_OBJECT_HXX_ +#include "object.hxx" +#endif + +#ifndef _STORE_STORBASE_HXX_ +#include "storbase.hxx" +#endif +#ifndef _STORE_STORDATA_HXX_ +#include "stordata.hxx" +#endif +#ifndef _STORE_STORPAGE_HXX_ +#include "storpage.hxx" +#endif + +using namespace store; + +/*======================================================================== + * + * OStore... internals. + * + *======================================================================*/ +/* + * __store_convertTextToUnicode. + */ +inline sal_Size __store_convertTextToUnicode ( + rtl_TextToUnicodeConverter hConverter, + const sal_Char *pSrcBuffer, sal_Size nSrcLength, + sal_Unicode *pDstBuffer, sal_Size nDstLength) +{ + sal_uInt32 nCvtInfo = 0; + sal_Size nCvtBytes = 0; + return rtl_convertTextToUnicode ( + hConverter, 0, + pSrcBuffer, nSrcLength, + pDstBuffer, nDstLength, + OSTRING_TO_OUSTRING_CVTFLAGS, + &nCvtInfo, &nCvtBytes); +} + +/*======================================================================== + * + * OStoreDirectory_Impl implementation. + * + *======================================================================*/ +const sal_uInt32 OStoreDirectory_Impl::m_nTypeId = sal_uInt32(0x89191107); + +/* + * OStoreDirectory_Impl. + */ +OStoreDirectory_Impl::OStoreDirectory_Impl (void) + : m_xManager (), + m_aDescr (0, 0, 0), + m_nPath (0), + m_hTextCvt (NULL) +{} + +/* + * ~OStoreDirectory_Impl. + */ +OStoreDirectory_Impl::~OStoreDirectory_Impl (void) +{ + if (m_xManager.is()) + { + if (m_aDescr.m_nAddr != STORE_PAGE_NULL) + m_xManager->releasePage (m_aDescr, store_AccessReadOnly); + } + rtl_destroyTextToUnicodeConverter (m_hTextCvt); +} + +/* + * isKindOf. + */ +sal_Bool SAL_CALL OStoreDirectory_Impl::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == m_nTypeId); +} + +/* + * create. + */ +storeError OStoreDirectory_Impl::create ( + OStorePageManager *pManager, + rtl_String *pPath, + rtl_String *pName, + storeAccessMode eMode) +{ + rtl::Reference<OStorePageManager> xManager (pManager); + if (!xManager.is()) + return store_E_InvalidAccess; + + if (!(pPath && pName)) + return store_E_InvalidParameter; + + OStoreDirectoryPageObject aPage; + storeError eErrCode = xManager->iget ( + aPage, STORE_ATTRIB_ISDIR, + pPath, pName, eMode); + if (eErrCode != store_E_None) + return eErrCode; + + if (!(aPage.attrib() & STORE_ATTRIB_ISDIR)) + return store_E_NotDirectory; + + inode_holder_type xNode (aPage.get()); + eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadOnly); + if (eErrCode != store_E_None) + return eErrCode; + + // Evaluate iteration path. + m_nPath = aPage.path(); + m_nPath = rtl_crc32 (m_nPath, "/", 1); + + // Save page manager, and descriptor. + m_xManager = xManager; + m_aDescr = xNode->m_aDescr; + + return store_E_None; +} + +/* + * iterate. + */ +storeError OStoreDirectory_Impl::iterate (storeFindData &rFindData) +{ + if (!m_xManager.is()) + return store_E_InvalidAccess; + + storeError eErrCode = store_E_NoMoreFiles; + if (!rFindData.m_nReserved) + return eErrCode; + + // Acquire exclusive access. + osl::MutexGuard aGuard (*m_xManager); + + // Check TextConverter. + if (m_hTextCvt == NULL) + m_hTextCvt = rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_UTF8); + + // Setup iteration key. + OStorePageKey aKey (rFindData.m_nReserved, m_nPath); + + // Iterate. + for (;;) + { + OStorePageLink aLink; + eErrCode = m_xManager->iterate (aKey, aLink, rFindData.m_nAttrib); + if (!((eErrCode == store_E_None) && (aKey.m_nHigh == store::htonl(m_nPath)))) + break; + + if (!(rFindData.m_nAttrib & STORE_ATTRIB_ISLINK)) + { + // Load page. + OStoreDirectoryPageObject aPage; + eErrCode = m_xManager->loadObjectAt (aPage, aLink.location()); + if (eErrCode == store_E_None) + { + inode_holder_type xNode (aPage.get()); + + // Setup FindData. + sal_Char *p = xNode->m_aNameBlock.m_pData; + sal_Size n = rtl_str_getLength (p); + sal_Size k = rFindData.m_nLength; + + n = __store_convertTextToUnicode ( + m_hTextCvt, p, n, + rFindData.m_pszName, STORE_MAXIMUM_NAMESIZE - 1); + if (k > n) + { + k = (k - n) * sizeof(sal_Unicode); + memset (&rFindData.m_pszName[n], 0, k); + } + + rFindData.m_nLength = n; + rFindData.m_nAttrib |= aPage.attrib(); + rFindData.m_nSize = aPage.dataLength(); + + // Leave. + rFindData.m_nReserved = store::ntohl(aKey.m_nLow); + return store_E_None; + } + } + + if (aKey.m_nLow == 0) + break; + aKey.m_nLow = store::htonl(store::ntohl(aKey.m_nLow) - 1); + } + + // Finished. + memset (&rFindData, 0, sizeof (storeFindData)); + return store_E_NoMoreFiles; +} diff --git a/store/source/stordir.hxx b/store/source/stordir.hxx new file mode 100644 index 000000000000..acfbf36af8d6 --- /dev/null +++ b/store/source/stordir.hxx @@ -0,0 +1,157 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: stordir.hxx,v $ + * + * $Revision: 1.1.2.2 $ + * + * last change: $Author: mhu $ $Date: 2008/10/17 16:30:17 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef _STORE_STORDIR_HXX_ +#define _STORE_STORDIR_HXX_ "$Revision: 1.1.2.2 $" + +#ifndef _SAL_TYPES_H_ +#include <sal/types.h> +#endif + +#ifndef _RTL_TEXTCVT_H_ +#include <rtl/textcvt.h> +#endif +#ifndef _RTL_STRING_H_ +#include <rtl/string.h> +#endif +#ifndef _RTL_REF_HXX_ +#include <rtl/ref.hxx> +#endif + +#ifndef _STORE_OBJECT_HXX_ +#include "object.hxx" +#endif +#ifndef _STORE_STORBASE_HXX_ +#include "storbase.hxx" +#endif +#ifndef _STORE_STORPAGE_HXX_ +#include "storpage.hxx" +#endif + +namespace store +{ + +struct OStoreDirectoryPageData; + +/*======================================================================== + * + * OStoreDirectory_Impl interface. + * + *======================================================================*/ +class OStoreDirectory_Impl : public store::OStoreObject +{ +public: + /** Construction. + */ + OStoreDirectory_Impl (void); + + /** create (two-phase construction). + * @param pManager [in] + * @param pPath [in] + * @param pName [in] + * @param eAccessMode [in] + * @return store_E_None upon success. + */ + storeError create ( + OStorePageManager *pManager, + rtl_String *pPath, + rtl_String *pName, + storeAccessMode eAccessMode); + + /** iterate. + * @param rFindData [out] + * @return store_E_None upon success, + * store_E_NoMoreFiles upon end of iteration. + */ + storeError iterate ( + storeFindData &rFindData); + + /** IStoreHandle. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId); + +protected: + /** Destruction. + */ + virtual ~OStoreDirectory_Impl (void); + +private: + /** IStoreHandle TypeId. + */ + static const sal_uInt32 m_nTypeId; + + /** IStoreHandle query() template function specialization. + */ + friend OStoreDirectory_Impl* + SAL_CALL query<> (IStoreHandle *pHandle, OStoreDirectory_Impl*); + + /** Representation. + */ + typedef OStoreDirectoryPageData inode; + typedef PageHolderObject< inode > inode_holder_type; + + rtl::Reference<OStorePageManager> m_xManager; + + OStorePageDescriptor m_aDescr; + sal_uInt32 m_nPath; + rtl_TextToUnicodeConverter m_hTextCvt; + + /** Not implemented. + */ + OStoreDirectory_Impl (const OStoreDirectory_Impl&); + OStoreDirectory_Impl& operator= (const OStoreDirectory_Impl&); +}; + +template<> inline OStoreDirectory_Impl* +SAL_CALL query (IStoreHandle *pHandle, OStoreDirectory_Impl*) +{ + if (pHandle && pHandle->isKindOf (OStoreDirectory_Impl::m_nTypeId)) + { + // Handle is kind of OStoreDirectory_Impl. + return static_cast<OStoreDirectory_Impl*>(pHandle); + } + return 0; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORDIR_HXX_ */ + diff --git a/store/source/store.cxx b/store/source/store.cxx new file mode 100644 index 000000000000..db27f7cbb05b --- /dev/null +++ b/store/source/store.cxx @@ -0,0 +1,768 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: store.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "store/store.h" + +#include <sal/types.h> +#include <rtl/memory.h> +#include <rtl/string.hxx> +#include <rtl/ref.hxx> + +#include "object.hxx" +#include "lockbyte.hxx" + +#include "storbase.hxx" +#include "storpage.hxx" +#include "stordir.hxx" +#include "storlckb.hxx" + +using rtl::Reference; +using rtl::OString; + +namespace store +{ +/** Template helper class as type safe Reference to store_handle_type. + */ +template<class store_handle_type> +class OStoreHandle : public rtl::Reference<store_handle_type> +{ +public: + OStoreHandle (store_handle_type * pHandle) + : rtl::Reference<store_handle_type> (pHandle) + {} + + static store_handle_type * SAL_CALL query (void * pHandle) + { + return store::query ( + static_cast<IStoreHandle*>(pHandle), + static_cast<store_handle_type*>(0)); + } +}; +} + + +using namespace store; + +/*======================================================================== + * + * storeHandle implementation. + * + *======================================================================*/ +/* + * store_acquireHandle. + */ +storeError SAL_CALL store_acquireHandle ( + storeHandle Handle +) SAL_THROW_EXTERN_C() +{ + IStoreHandle *pHandle = static_cast<IStoreHandle*>(Handle); + if (!pHandle) + return store_E_InvalidHandle; + + pHandle->acquire(); + return store_E_None; +} + +/* + * store_releaseHandle. + */ +storeError SAL_CALL store_releaseHandle ( + storeHandle Handle +) SAL_THROW_EXTERN_C() +{ + IStoreHandle *pHandle = static_cast<IStoreHandle*>(Handle); + if (!pHandle) + return store_E_InvalidHandle; + + pHandle->release(); + return store_E_None; +} + +/*======================================================================== + * + * storeFileHandle implementation. + * + *======================================================================*/ +/* + * store_createMemoryFile. + */ +storeError SAL_CALL store_createMemoryFile ( + sal_uInt16 nPageSize, + storeFileHandle *phFile +) SAL_THROW_EXTERN_C() +{ + if (!phFile) + return store_E_InvalidParameter; + *phFile = NULL; + + Reference<ILockBytes> xLockBytes; + + storeError eErrCode = MemoryLockBytes_createInstance(xLockBytes); + if (eErrCode != store_E_None) + return eErrCode; + OSL_ASSERT(xLockBytes.is()); + + Reference<OStorePageManager> xManager (new OStorePageManager()); + if (!xManager.is()) + return store_E_OutOfMemory; + + eErrCode = xManager->initialize ( + &*xLockBytes, store_AccessCreate, nPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + xManager->acquire(); + + *phFile = (storeFileHandle)&(*xManager); + return store_E_None; +} + +/* + * store_openFile. + */ +storeError SAL_CALL store_openFile ( + rtl_uString *pFilename, + storeAccessMode eAccessMode, + sal_uInt16 nPageSize, + storeFileHandle *phFile +) SAL_THROW_EXTERN_C() +{ + if (phFile) + *phFile = NULL; + + if (!(pFilename && phFile)) + return store_E_InvalidParameter; + + Reference<ILockBytes> xLockBytes; + + storeError eErrCode = FileLockBytes_createInstance (xLockBytes, pFilename, eAccessMode); + if (eErrCode != store_E_None) + return eErrCode; + OSL_ASSERT(xLockBytes.is()); + + Reference<OStorePageManager> xManager (new OStorePageManager()); + if (!xManager.is()) + return store_E_OutOfMemory; + + eErrCode = xManager->initialize ( + &*xLockBytes, eAccessMode, nPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + xManager->acquire(); + + *phFile = (storeFileHandle)&(*xManager); + return store_E_None; +} + +/* + * store_closeFile. + */ +storeError SAL_CALL store_closeFile ( + storeFileHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStorePageManager *pManager = + OStoreHandle<OStorePageManager>::query (Handle); + if (!pManager) + return store_E_InvalidHandle; + + storeError eErrCode = pManager->close(); + pManager->release(); + return eErrCode; +} + +/* + * store_flushFile. + */ +storeError SAL_CALL store_flushFile ( + storeFileHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + return xManager->flush(); +} + +/* + * store_getFileRefererCount. + */ +storeError SAL_CALL store_getFileRefererCount ( + storeFileHandle Handle, + sal_uInt32 *pnRefCount +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!pnRefCount) + return store_E_InvalidParameter; + + *pnRefCount = xManager->getRefererCount(); + return store_E_None; +} + +/* + * store_getFileSize. + */ +storeError SAL_CALL store_getFileSize ( + storeFileHandle Handle, + sal_uInt32 *pnSize +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!pnSize) + return store_E_InvalidParameter; + + return xManager->size (*pnSize); +} + +/* + * store_rebuildFile. + */ +storeError SAL_CALL store_rebuildFile ( + rtl_uString *pSrcFilename, + rtl_uString *pDstFilename +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + if (!(pSrcFilename && pDstFilename)) + return store_E_InvalidParameter; + + Reference<OStorePageManager> xManager (new OStorePageManager()); + if (!xManager.is()) + return store_E_OutOfMemory; + + Reference<ILockBytes> xSrcLB; + eErrCode = FileLockBytes_createInstance (xSrcLB, pSrcFilename, store_AccessReadOnly); + if (eErrCode != store_E_None) + return eErrCode; + OSL_ASSERT(xSrcLB.is()); + + Reference<ILockBytes> xDstLB; + eErrCode = FileLockBytes_createInstance (xDstLB, pDstFilename, store_AccessCreate); + if (eErrCode != store_E_None) + return eErrCode; + OSL_ASSERT(xDstLB.is()); + + return xManager->rebuild (&*xSrcLB, &*xDstLB); +} + +/*======================================================================== + * + * storeDirectoryHandle implementation. + * + *======================================================================*/ +/* + * store_openDirectory. + */ +storeError SAL_CALL store_openDirectory ( + storeFileHandle hFile, + rtl_uString *pPath, + rtl_uString *pName, + storeAccessMode eAccessMode, + storeDirectoryHandle *phDirectory +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + if (phDirectory) + *phDirectory = NULL; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (hFile)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pPath && pName && phDirectory)) + return store_E_InvalidParameter; + + Reference<OStoreDirectory_Impl> xDirectory (new OStoreDirectory_Impl()); + if (!xDirectory.is()) + return store_E_OutOfMemory; + + OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8); + OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8); + + eErrCode = xDirectory->create (&*xManager, aPath.pData, aName.pData, eAccessMode); + if (eErrCode != store_E_None) + return eErrCode; + + xDirectory->acquire(); + + *phDirectory = (storeDirectoryHandle)&(*xDirectory); + return store_E_None; +} + +/* + * store_closeDirectory. + */ +storeError SAL_CALL store_closeDirectory ( + storeDirectoryHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStoreDirectory_Impl *pDirectory = + OStoreHandle<OStoreDirectory_Impl>::query (Handle); + if (!pDirectory) + return store_E_InvalidHandle; + + pDirectory->release(); + return store_E_None; +} + +/* + * store_findFirst. + */ +storeError SAL_CALL store_findFirst ( + storeDirectoryHandle Handle, + storeFindData *pFindData +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreDirectory_Impl> xDirectory ( + OStoreHandle<OStoreDirectory_Impl>::query (Handle)); + if (!xDirectory.is()) + return store_E_InvalidHandle; + + if (!pFindData) + return store_E_InvalidParameter; + + // Initialize FindData. + rtl_zeroMemory (pFindData, sizeof (storeFindData)); + + // Find first. + pFindData->m_nReserved = (sal_uInt32)(~0); + return xDirectory->iterate (*pFindData); +} + +/* + * store_findNext. + */ +storeError SAL_CALL store_findNext ( + storeDirectoryHandle Handle, + storeFindData *pFindData +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreDirectory_Impl> xDirectory ( + OStoreHandle<OStoreDirectory_Impl>::query (Handle)); + if (!xDirectory.is()) + return store_E_InvalidHandle; + + if (!pFindData) + return store_E_InvalidParameter; + + // Check FindData. + if (!pFindData->m_nReserved) + return store_E_NoMoreFiles; + + // Find next. + pFindData->m_nReserved -= 1; + return xDirectory->iterate (*pFindData); +} + +/*======================================================================== + * + * storeStreamHandle implementation. + * + *======================================================================*/ +/* + * store_openStream + */ +storeError SAL_CALL store_openStream ( + storeFileHandle hFile, + rtl_uString *pPath, + rtl_uString *pName, + storeAccessMode eAccessMode, + storeStreamHandle *phStream +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + if (phStream) + *phStream = NULL; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (hFile)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pPath && pName && phStream)) + return store_E_InvalidParameter; + + Reference<OStoreLockBytes> xLockBytes (new OStoreLockBytes()); + if (!xLockBytes.is()) + return store_E_OutOfMemory; + + OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8); + OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8); + + eErrCode = xLockBytes->create (&*xManager, aPath.pData, aName.pData, eAccessMode); + if (eErrCode != store_E_None) + return eErrCode; + + xLockBytes->acquire(); + + *phStream = (storeStreamHandle)&(*xLockBytes); + return store_E_None; +} + +/* + * store_closeStream. + */ +storeError SAL_CALL store_closeStream ( + storeStreamHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStoreLockBytes *pLockBytes = + OStoreHandle<OStoreLockBytes>::query (Handle); + if (!pLockBytes) + return store_E_InvalidHandle; + + pLockBytes->release(); + return store_E_None; +} + +/* + * store_readStream. + */ +storeError SAL_CALL store_readStream ( + storeStreamHandle Handle, + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 *pnDone +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + if (!(pBuffer && pnDone)) + return store_E_InvalidParameter; + + return xLockBytes->readAt (nOffset, pBuffer, nBytes, *pnDone); +} + +/* + * store_writeStream. + */ +storeError SAL_CALL store_writeStream ( + storeStreamHandle Handle, + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 *pnDone +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + if (!(pBuffer && pnDone)) + return store_E_InvalidParameter; + + return xLockBytes->writeAt (nOffset, pBuffer, nBytes, *pnDone); +} + +/* + * store_flushStream. + */ +storeError SAL_CALL store_flushStream ( + storeStreamHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + return xLockBytes->flush(); +} + +/* + * store_getStreamSize. + */ +storeError SAL_CALL store_getStreamSize ( + storeStreamHandle Handle, + sal_uInt32 *pnSize +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + if (!pnSize) + return store_E_InvalidParameter; + + return xLockBytes->stat (*pnSize); +} + +/* + * store_setStreamSize. + */ +storeError SAL_CALL store_setStreamSize ( + storeStreamHandle Handle, + sal_uInt32 nSize +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + return xLockBytes->setSize (nSize); +} + +/*======================================================================== + * + * Common storeDirectoryHandle and storeStreamHandle operations. + * + *======================================================================*/ +/* + * store_attrib. + */ +storeError SAL_CALL store_attrib ( + storeFileHandle Handle, + rtl_uString *pPath, + rtl_uString *pName, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 *pnAttrib +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + if (pnAttrib) + *pnAttrib = 0; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pPath && pName)) + return store_E_InvalidParameter; + + // Setup page key. + OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8); + OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aKey; + + eErrCode = OStorePageManager::namei (aPath.pData, aName.pData, aKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Obtain or modify page attributes. + sal_uInt32 nAttrib = 0; + eErrCode = xManager->attrib (aKey, nMask1, nMask2, nAttrib); + if (pnAttrib) + *pnAttrib = nAttrib; + return eErrCode; +} + +/* + * store_link. + */ +storeError SAL_CALL store_link ( + storeFileHandle Handle, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pSrcPath && pSrcName)) + return store_E_InvalidParameter; + + if (!(pDstPath && pDstName)) + return store_E_InvalidParameter; + + // Setup 'Source' page key. + OString aSrcPath ( + pSrcPath->buffer, pSrcPath->length, RTL_TEXTENCODING_UTF8); + OString aSrcName ( + pSrcName->buffer, pSrcName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aSrcKey; + + eErrCode = OStorePageManager::namei ( + aSrcPath.pData, aSrcName.pData, aSrcKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Setup 'Destination' page key. + OString aDstPath ( + pDstPath->buffer, pDstPath->length, RTL_TEXTENCODING_UTF8); + OString aDstName ( + pDstName->buffer, pDstName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aDstKey; + + eErrCode = OStorePageManager::namei ( + aDstPath.pData, aDstName.pData, aDstKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Link 'Source' hard to 'Destination'. + return xManager->link (aSrcKey, aDstKey); +} + +/* + * store_symlink. + */ +storeError SAL_CALL store_symlink ( + storeFileHandle Handle, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pSrcPath && pSrcName)) + return store_E_InvalidParameter; + + if (!(pDstPath && pDstName)) + return store_E_InvalidParameter; + + // Setup 'Destination' page key. + OString aDstPath ( + pDstPath->buffer, pDstPath->length, RTL_TEXTENCODING_UTF8); + OString aDstName ( + pDstName->buffer, pDstName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aDstKey; + + eErrCode = OStorePageManager::namei ( + aDstPath.pData, aDstName.pData, aDstKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert 'Source' as symlink to 'Destination'. + OString aSrcPath ( + pSrcPath->buffer, pSrcPath->length, RTL_TEXTENCODING_UTF8); + OString aSrcName ( + pSrcName->buffer, pSrcName->length, RTL_TEXTENCODING_UTF8); + + return xManager->symlink (aSrcPath.pData, aSrcName.pData, aDstKey); +} + +/* + * store_rename. + */ +storeError SAL_CALL store_rename ( + storeFileHandle Handle, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pSrcPath && pSrcName)) + return store_E_InvalidParameter; + + if (!(pDstPath && pDstName)) + return store_E_InvalidParameter; + + // Setup 'Source' page key. + OString aSrcPath ( + pSrcPath->buffer, pSrcPath->length, RTL_TEXTENCODING_UTF8); + OString aSrcName ( + pSrcName->buffer, pSrcName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aSrcKey; + + eErrCode = OStorePageManager::namei ( + aSrcPath.pData, aSrcName.pData, aSrcKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Rename 'Source' into 'Destination'. + OString aDstPath ( + pDstPath->buffer, pDstPath->length, RTL_TEXTENCODING_UTF8); + OString aDstName ( + pDstName->buffer, pDstName->length, RTL_TEXTENCODING_UTF8); + + return xManager->rename (aSrcKey, aDstPath.pData, aDstName.pData); +} + +/* + * store_remove. + */ +storeError SAL_CALL store_remove ( + storeFileHandle Handle, + rtl_uString *pPath, + rtl_uString *pName +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pPath && pName)) + return store_E_InvalidParameter; + + // Setup page key. + OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8); + OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aKey; + + eErrCode = OStorePageManager::namei (aPath.pData, aName.pData, aKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Remove. + return xManager->remove (aKey); +} diff --git a/store/source/storlckb.cxx b/store/source/storlckb.cxx new file mode 100644 index 000000000000..fc028f1da688 --- /dev/null +++ b/store/source/storlckb.cxx @@ -0,0 +1,454 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storlckb.cxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storlckb.hxx" + +#include "sal/types.h" +#include "sal/macros.h" +#include "rtl/string.h" +#include "rtl/ref.hxx" +#include "osl/mutex.hxx" + +#include "store/types.h" +#include "object.hxx" + +#include "storbase.hxx" +#include "stordata.hxx" +#include "storpage.hxx" + +using namespace store; + +/*======================================================================== + * + * OStoreLockBytes implementation. + * + *======================================================================*/ +const sal_uInt32 OStoreLockBytes::m_nTypeId = sal_uInt32(0x94190310); + +/* + * OStoreLockBytes. + */ +OStoreLockBytes::OStoreLockBytes (void) + : m_xManager (), + m_xNode (), + m_bWriteable (false) +{ +} + +/* + * ~OStoreLockBytes. + */ +OStoreLockBytes::~OStoreLockBytes (void) +{ + if (m_xManager.is()) + { + if (m_xNode.is()) + { + OStorePageDescriptor aDescr (m_xNode->m_aDescr); + if (m_bWriteable) + m_xManager->releasePage (aDescr, store_AccessReadWrite); + else + m_xManager->releasePage (aDescr, store_AccessReadOnly); + } + } +} + +/* + * isKindOf. + */ +sal_Bool SAL_CALL OStoreLockBytes::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == m_nTypeId); +} + +/* + * create. + */ +storeError OStoreLockBytes::create ( + OStorePageManager *pManager, + rtl_String *pPath, + rtl_String *pName, + storeAccessMode eMode) +{ + rtl::Reference<OStorePageManager> xManager (pManager); + if (!xManager.is()) + return store_E_InvalidAccess; + + if (!(pPath && pName)) + return store_E_InvalidParameter; + + OStoreDirectoryPageObject aPage; + storeError eErrCode = xManager->iget ( + aPage, STORE_ATTRIB_ISFILE, + pPath, pName, eMode); + if (eErrCode != store_E_None) + return eErrCode; + + if (!(aPage.attrib() & STORE_ATTRIB_ISFILE)) + { + // No ISFILE in older versions (backward compatibility). + if (aPage.attrib() & STORE_ATTRIB_ISLINK) + return store_E_NotFile; + } + + // ... + inode_holder_type xNode (aPage.get()); + if (eMode != store_AccessReadOnly) + eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadWrite); + else + eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadOnly); + if (eErrCode != store_E_None) + return eErrCode; + + // ... + m_xManager = xManager; + m_xNode = xNode; + m_bWriteable = (eMode != store_AccessReadOnly); + + // Check for truncation. + if (eMode == store_AccessCreate) + { + // Truncate to zero length. + eErrCode = setSize(0); + } + return eErrCode; +} + +/* + * readAt. + */ +storeError OStoreLockBytes::readAt ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone) +{ + rnDone = 0; + + if (!m_xManager.is()) + return store_E_InvalidAccess; + + if (!pBuffer) + return store_E_InvalidParameter; + if (!nBytes) + return store_E_None; + + // Acquire exclusive access. + osl::MutexGuard aGuard (*m_xManager); + + // Determine data length. + OStoreDirectoryPageObject aPage (m_xNode.get()); + + sal_uInt32 nDataLen = aPage.dataLength(); + if ((nOffset + nBytes) > nDataLen) + nBytes = nDataLen - nOffset; + + // Read data. + OStoreDataPageObject aData; + sal_uInt8 *pData = (sal_uInt8*)pBuffer; + while ((0 < nBytes) && (nOffset < nDataLen)) + { + // Determine 'Offset' scope. + inode::ChunkScope eScope = m_xNode->scope (nOffset); + if (eScope == inode::SCOPE_INTERNAL) + { + // Read from inode page (internal scope). + inode::ChunkDescriptor aDescr ( + nOffset, m_xNode->capacity()); + + sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); + nLength = SAL_MIN(nLength, nBytes); + + memcpy ( + &pData[rnDone], + &m_xNode->m_pData[aDescr.m_nOffset], + nLength); + + // Adjust counters. + rnDone += nLength; + nOffset += nLength; + nBytes -= nLength; + } + else + { + // Read from data page (external scope). + inode::ChunkDescriptor aDescr ( + nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ + + sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); + nLength = SAL_MIN(nLength, nBytes); + + storeError eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_NotExists) + return eErrCode; + + memset ( + &pData[rnDone], + 0, + nLength); + } + else + { + PageHolderObject< data > xData (aData.makeHolder<data>()); + memcpy ( + &pData[rnDone], + &xData->m_pData[aDescr.m_nOffset], + nLength); + } + + // Adjust counters. + rnDone += nLength; + nOffset += nLength; + nBytes -= nLength; + } + } + + // Done. + return store_E_None; +} + +/* + * writeAt. + */ +storeError OStoreLockBytes::writeAt ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone) +{ + rnDone = 0; + + if (!m_xManager.is()) + return store_E_InvalidAccess; + if (!m_bWriteable) + return store_E_AccessViolation; + + if (!pBuffer) + return store_E_InvalidParameter; + if (!nBytes) + return store_E_None; + + // Acquire exclusive access. + osl::MutexGuard aGuard (*m_xManager); + + // Write data. + OStoreDirectoryPageObject aPage (m_xNode.get()); + const sal_uInt8 *pData = (const sal_uInt8*)pBuffer; + + storeError eErrCode = store_E_None; + while (nBytes > 0) + { + // Determine 'Offset' scope. + inode::ChunkScope eScope = m_xNode->scope (nOffset); + if (eScope == inode::SCOPE_INTERNAL) + { + // Write to inode page (internal scope). + inode::ChunkDescriptor aDescr ( + nOffset, m_xNode->capacity()); + + sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); + nLength = SAL_MIN(nLength, nBytes); + + memcpy ( + &m_xNode->m_pData[aDescr.m_nOffset], + &pData[rnDone], nLength); + + // Mark inode dirty. + aPage.touch(); + + // Adjust counters. + rnDone += nLength; + nOffset += nLength; + nBytes -= nLength; + + // Adjust data length. + if (aPage.dataLength() < nOffset) + aPage.dataLength (nOffset); + } + else + { + // Write to data page (external scope). + OStoreDataPageObject aData; + + inode::ChunkDescriptor aDescr ( + nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ + + sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); + if ((aDescr.m_nOffset > 0) || (nBytes < nLength)) + { + // Unaligned. Need to load/create data page. +// @@@ loadOrCreate() + eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_NotExists) + return eErrCode; + + eErrCode = aData.construct<data>(m_xManager->allocator()); + if (eErrCode != store_E_None) + return eErrCode; + } + } + + PageHolderObject< data > xData (aData.makeHolder<data>()); + if (!xData.is()) + { + eErrCode = aData.construct<data>(m_xManager->allocator()); + if (eErrCode != store_E_None) + return eErrCode; + xData = aData.makeHolder<data>(); + } + + // Modify data page. + nLength = SAL_MIN(nLength, nBytes); + memcpy ( + &xData->m_pData[aDescr.m_nOffset], + &pData[rnDone], nLength); + + // Save data page. + eErrCode = aPage.write (aDescr.m_nPage, aData, *m_xManager); + if (eErrCode != store_E_None) + return eErrCode; + + // Adjust counters. + rnDone += nLength; + nOffset += nLength; + nBytes -= nLength; + + // Adjust data length. + if (aPage.dataLength() < nOffset) + aPage.dataLength (nOffset); + } + } + + // Check for modified inode. + if (aPage.dirty()) + return m_xManager->saveObjectAt (aPage, aPage.location()); + else + return store_E_None; +} + +/* + * flush. + */ +storeError OStoreLockBytes::flush (void) +{ + if (!m_xManager.is()) + return store_E_InvalidAccess; + + return m_xManager->flush(); +} + +/* + * setSize. + */ +storeError OStoreLockBytes::setSize (sal_uInt32 nSize) +{ + if (!m_xManager.is()) + return store_E_InvalidAccess; + if (!m_bWriteable) + return store_E_AccessViolation; + + // Acquire exclusive access. + osl::MutexGuard aGuard (*m_xManager); + + // Determine current length. + OStoreDirectoryPageObject aPage (m_xNode.get()); + sal_uInt32 nDataLen = aPage.dataLength(); + + if (nSize == nDataLen) + return store_E_None; + + if (nSize < nDataLen) + { + // Truncate. + storeError eErrCode = store_E_None; + + // Determine 'Size' scope. + inode::ChunkScope eSizeScope = m_xNode->scope (nSize); + if (eSizeScope == inode::SCOPE_INTERNAL) + { + // Internal 'Size' scope. Determine 'Data' scope. + inode::ChunkScope eDataScope = m_xNode->scope (nDataLen); + if (eDataScope == inode::SCOPE_EXTERNAL) + { + // External 'Data' scope. Truncate all external data pages. + eErrCode = aPage.truncate (0, *m_xManager); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Truncate internal data page. + inode::ChunkDescriptor aDescr (nSize, m_xNode->capacity()); + memset ( + &(m_xNode->m_pData[aDescr.m_nOffset]), + 0, aDescr.m_nLength); + } + else + { + // External 'Size' scope. Truncate external data pages. + inode::ChunkDescriptor aDescr ( + nSize - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ + + sal_uInt32 nPage = aDescr.m_nPage; + if (aDescr.m_nOffset) nPage += 1; + + eErrCode = aPage.truncate (nPage, *m_xManager); + if (eErrCode != store_E_None) + return eErrCode; + } + } + + // Set (extended or truncated) size. + aPage.dataLength (nSize); + + // Save modified inode. + return m_xManager->saveObjectAt (aPage, aPage.location()); +} + +/* + * stat. + */ +storeError OStoreLockBytes::stat (sal_uInt32 &rnSize) +{ + rnSize = 0; + + if (!m_xManager.is()) + return store_E_InvalidAccess; + + OStoreDirectoryPageObject aPage (m_xNode.get()); + rnSize = aPage.dataLength(); + return store_E_None; +} diff --git a/store/source/storlckb.hxx b/store/source/storlckb.hxx new file mode 100644 index 000000000000..4a0dbfde873a --- /dev/null +++ b/store/source/storlckb.hxx @@ -0,0 +1,174 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storlckb.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORLCKB_HXX_ +#define _STORE_STORLCKB_HXX_ "$Revision: 1.6.8.1 $" + +#include "sal/types.h" + +#include "rtl/ustring.h" +#include "rtl/ref.hxx" + +#include "object.hxx" +#include "storbase.hxx" +#include "storpage.hxx" + +namespace store +{ + +struct OStoreDataPageData; +struct OStoreDirectoryPageData; + +/*======================================================================== + * + * OStoreLockBytes interface. + * + *======================================================================*/ +class OStoreLockBytes : public store::OStoreObject +{ +public: + /** Construction. + */ + OStoreLockBytes (void); + + /** create (two-phase construction). + * @param pManager [in] + * @param pPath [in] + * @param pName [in] + * @param eMode [in] + * @return store_E_None upon success + */ + storeError create ( + OStorePageManager *pManager, + rtl_String *pPath, + rtl_String *pName, + storeAccessMode eAccessMode); + + /** Read at Offset into Buffer. + * @param nOffset [in] + * @param pBuffer [out] + * @param nBytes [in] + * @param rnDone [out] + * @return store_E_None upon success + */ + storeError readAt ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone); + + /** Write at Offset from Buffer. + * @param nOffset [in] + * @param pBuffer [in] + * @param nBytes [in] + * @param rnDone [out] + * @return store_E_None upon success + */ + storeError writeAt ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone); + + /** flush. + * @return store_E_None upon success + */ + storeError flush (void); + + /** setSize. + * @param nSize [in] + * @return store_E_None upon success + */ + storeError setSize (sal_uInt32 nSize); + + /** stat. + * @paran rnSize [out] + * @return store_E_None upon success + */ + storeError stat (sal_uInt32 &rnSize); + + /** IStoreHandle. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nMagic); + +protected: + /** Destruction (OReference). + */ + virtual ~OStoreLockBytes (void); + +private: + /** IStoreHandle TypeId. + */ + static const sal_uInt32 m_nTypeId; + + /** IStoreHandle query() template specialization. + */ + friend OStoreLockBytes* + SAL_CALL query<> (IStoreHandle *pHandle, OStoreLockBytes*); + + /** Representation. + */ + rtl::Reference<OStorePageManager> m_xManager; + + typedef OStoreDataPageData data; + typedef OStoreDirectoryPageData inode; + + typedef PageHolderObject< inode > inode_holder_type; + inode_holder_type m_xNode; + + bool m_bWriteable; + + /** Not implemented. + */ + OStoreLockBytes (const OStoreLockBytes&); + OStoreLockBytes& operator= (const OStoreLockBytes&); +}; + +template<> inline OStoreLockBytes* +SAL_CALL query (IStoreHandle *pHandle, OStoreLockBytes*) +{ + if (pHandle && pHandle->isKindOf (OStoreLockBytes::m_nTypeId)) + { + // Handle is kind of OStoreLockBytes. + return static_cast<OStoreLockBytes*>(pHandle); + } + return 0; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORLCKB_HXX_ */ + diff --git a/store/source/storpage.cxx b/store/source/storpage.cxx new file mode 100644 index 000000000000..b112d5bb8fdd --- /dev/null +++ b/store/source/storpage.cxx @@ -0,0 +1,1066 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storpage.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storpage.hxx" + +#include "sal/types.h" +#include "rtl/string.h" +#include "rtl/ref.hxx" +#include "osl/diagnose.h" +#include "osl/mutex.hxx" + +#include "store/types.h" + +#include "object.hxx" +#include "lockbyte.hxx" + +#include "storbase.hxx" +#include "stordata.hxx" +#include "stortree.hxx" + +using namespace store; + +/*======================================================================== + * + * OStorePageManager implementation. + * + *======================================================================*/ +const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120); + +/* + * OStorePageManager. + */ +OStorePageManager::OStorePageManager (void) +{ +} + +/* + * ~OStorePageManager. + */ +OStorePageManager::~OStorePageManager (void) +{ +} + +/* + * isKindOf. + */ +sal_Bool SAL_CALL OStorePageManager::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == m_nTypeId); +} + +/* + * initialize (two-phase construction). + * Precond: none. + */ +storeError OStorePageManager::initialize ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check arguments. + if (!pLockBytes) + return store_E_InvalidParameter; + + // Initialize base. + storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for (not) writeable. + if (!base::isWriteable()) + { + // Readonly. Load RootNode. + return base::loadObjectAt (m_aRoot, rnPageSize); + } + + // Writeable. Load or Create RootNode. + eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this); + if (eErrCode == store_E_Pending) + { + // Creation notification. + PageHolderObject< page > xRoot (m_aRoot.get()); + + // Pre-allocate left most entry (ugly, but we can't insert to left). + OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0); + xRoot->insert (0, entry(aKey)); + + // Save RootNode. + eErrCode = base::saveObjectAt (m_aRoot, rnPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Flush for robustness. + (void) base::flush(); + } + + // Done. + return eErrCode; +} + +/* + * find_lookup (w/o split()). + * Internal: Precond: initialized, readable, exclusive access. + */ +storeError OStorePageManager::find_lookup ( + OStoreBTreeNodeObject & rNode, + sal_uInt16 & rIndex, + OStorePageKey const & rKey) +{ + // Find Node and Index. + storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // Greater or Equal. + PageHolderObject< page > xPage (rNode.get()); + OSL_POSTCOND(rIndex < xPage->usageCount(), "store::PageManager::find_lookup(): logic error"); + entry e (xPage->m_pData[rIndex]); + + // Check for exact match. + if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL) + { + // Page not present. + return store_E_NotExists; + } + + // Check address. + if (e.m_aLink.location() == STORE_PAGE_NULL) + { + // Page not present. + return store_E_NotExists; + } + + return store_E_None; +} + +/* + * remove_Impl (possibly down from root). + * Internal: Precond: initialized, writeable, exclusive access. + */ +#if 0 /* EXP */ +storeError OStorePageManager::remove_Impl (entry & rEntry) +{ + // Find Node and Index. + OStoreBTreeNodeObject aNode; + sal_uInt16 nIndex = 0; + eErrCode = m_aRoot.find_lookup (aNode, nIndex, entry::CompareGreater(rEntry), *this); + + // @@@ + + PageHolderObject< page > xPage (aNode.get()); + page & rPage = (*xPage); + + // Check current page index. + sal_uInt16 i = rPage.find (rEntry), n = rPage.usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Compare entry. + entry::CompareResult result = rEntry.compare (rPage.m_pData[i]); + + for (; result == entry::COMPARE_GREATER && xPage->depth() > 0; ) + { + // Check next node address. + sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location(); + if (nAddr == STORE_PAGE_NULL) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Load next node page. + eErrCode = loadObjectAt (aNode, nAddr); + + PageHolderObject< page > xNext (aNode.get()); + xNext.swap (xPage); + } + + aNode.remove (nIndex, rEntry, *this); + + + do + { + // Load next node page. + eErrCode = loadObjectAt (aNode, nAddr); + + page const & rPage = (*xPage); + + // Check current page index. + sal_uInt16 i = rPage.find (rEntry), n = rPage.usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Compare entry. + result = rEntry.compare (rPage.m_pData[i]); + + } while (result == entry::COMPATE_GREATER); +} +#endif /* EXP */ + +storeError OStorePageManager::remove_Impl (entry & rEntry) +{ + OStoreBTreeNodeObject aNode (m_aRoot.get()); + + // Check current page index. + PageHolderObject< page > xPage (aNode.get()); + sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Compare entry. + entry::CompareResult result = rEntry.compare (xPage->m_pData[i]); + + // Iterate down until equal match. + while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0)) + { + // Check link address. + sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location(); + if (nAddr == STORE_PAGE_NULL) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Load link page. + storeError eErrCode = loadObjectAt (aNode, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + PageHolderObject< page > xNext (aNode.get()); + xNext.swap (xPage); + + // Check index. + i = xPage->find (rEntry), n = xPage->usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Compare entry. + result = rEntry.compare (xPage->m_pData[i]); + } + + OSL_POSTCOND( + result != entry::COMPARE_LESS, + "OStorePageManager::remove(): find failed"); + + // Check entry comparison. + if (result == entry::COMPARE_LESS) + { + // Must not happen. + return store_E_Unknown; + } + + // Remove down from current page (recursive). + return aNode.remove (i, rEntry, *this); +} + +/* + * namei. + * Precond: none (static). + */ +storeError OStorePageManager::namei ( + const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey) +{ + // Check parameter. + if (!(pPath && pName)) + return store_E_InvalidParameter; + + // Check name length. + if (!(pName->length < STORE_MAXIMUM_NAMESIZE)) + return store_E_NameTooLong; + + // Transform pathname into key. + rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length)); + rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length)); + + // Done. + return store_E_None; +} + +/* + * iget. + * Precond: initialized. + */ +storeError OStorePageManager::iget ( + OStoreDirectoryPageObject & rPage, + sal_uInt32 nAttrib, + const rtl_String * pPath, + const rtl_String * pName, + storeAccessMode eMode) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + // Setup inode page key. + OStorePageKey aKey; + storeError eErrCode = namei (pPath, pName, aKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for directory. + if (nAttrib & STORE_ATTRIB_ISDIR) + { + // Ugly, but necessary (backward compatibility). + aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1)); + } + + // Load inode page. + eErrCode = load_dirpage_Impl (aKey, rPage); + if (eErrCode != store_E_None) + { + // Check mode and reason. + if (eErrCode != store_E_NotExists) + return eErrCode; + + if (eMode == store_AccessReadWrite) + return store_E_NotExists; + if (eMode == store_AccessReadOnly) + return store_E_NotExists; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Create inode page. + eErrCode = rPage.construct< inode >(base::allocator()); + if (eErrCode != store_E_None) + return eErrCode; + + // Setup inode nameblock. + PageHolderObject< inode > xPage (rPage.get()); + + rPage.key (aKey); + rPage.attrib (nAttrib); + + memcpy ( + &(xPage->m_aNameBlock.m_pData[0]), + pName->buffer, pName->length); + + // Save inode page. + eErrCode = save_dirpage_Impl (aKey, rPage); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Check for symbolic link. + if (rPage.attrib() & STORE_ATTRIB_ISLINK) + { + // Obtain 'Destination' page key. + PageHolderObject< inode > xPage (rPage.get()); + OStorePageKey aDstKey; + memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey)); + + // Load 'Destination' inode. + eErrCode = load_dirpage_Impl (aDstKey, rPage); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Done. + return store_E_None; +} + +/* + * iterate. + * Precond: initialized. + * ToDo: skip hardlink entries. + */ +storeError OStorePageManager::iterate ( + OStorePageKey & rKey, + OStorePageLink & rLink, + sal_uInt32 & rAttrib) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + // Find NodePage and Index. + OStoreBTreeNodeObject aNode; + sal_uInt16 i = 0; + storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // GreaterEqual. Found next entry. + PageHolderObject< page > xNode (aNode.get()); + entry e (xNode->m_pData[i]); + + // Setup result. + rKey = e.m_aKey; + rLink = e.m_aLink; + rAttrib = store::ntohl(e.m_nAttrib); + + // Done. + return store_E_None; +} + +/* + * load => private: iget() @@@ + * Internal: Precond: initialized, exclusive access. + */ +storeError OStorePageManager::load_dirpage_Impl ( + const OStorePageKey &rKey, + OStoreDirectoryPageObject &rPage) +{ + // Find Node and Index. + OStoreBTreeNodeObject aNode; + sal_uInt16 i = 0; + storeError eErrCode = find_lookup (aNode, i, rKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing entry. Load page. + PageHolderObject< page > xNode (aNode.get()); + entry e (xNode->m_pData[i]); + return loadObjectAt (rPage, e.m_aLink.location()); +} + +/* + * save => private: iget(), rebuild() @@@ + * Internal: Precond: initialized, writeable, exclusive access. + */ +storeError OStorePageManager::save_dirpage_Impl ( + const OStorePageKey &rKey, + OStoreDirectoryPageObject &rPage) +{ + // Find NodePage and Index. + node aNode; + sal_uInt16 i = 0; + + storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this); + PageHolderObject< page > xNode (aNode.get()); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_AlreadyExists) + return eErrCode; + + // Existing entry. + entry e (xNode->m_pData[i]); + if (e.m_aLink.location() != STORE_PAGE_NULL) + { + // Save page to existing location. + return saveObjectAt (rPage, e.m_aLink.location()); + } + + // Allocate page. + eErrCode = base::allocate (rPage); + if (eErrCode != store_E_None) + return eErrCode; + + // Update page location. + xNode->m_pData[i].m_aLink = rPage.location(); + + // Save modified NodePage. + return saveObjectAt (aNode, aNode.location()); + } + + // Allocate page. + eErrCode = base::allocate (rPage); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert. + OStorePageLink aLink (rPage.location()); + xNode->insert (i + 1, entry (rKey, aLink)); + + // Save modified NodePage. + return saveObjectAt (aNode, aNode.location()); +} + +/* + * attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)]. + * Precond: initialized. + */ +storeError OStorePageManager::attrib ( + const OStorePageKey &rKey, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 &rAttrib) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + // Find NodePage and index. + OStoreBTreeNodeObject aNode; + sal_uInt16 i = 0; + storeError eErrCode = find_lookup (aNode, i, rKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing entry. + PageHolderObject< page > xNode (aNode.get()); + entry e (xNode->m_pData[i]); + if (nMask1 != nMask2) + { + // Evaluate new attributes. + sal_uInt32 nAttrib = store::ntohl(e.m_nAttrib); + + nAttrib &= ~nMask1; + nAttrib |= nMask2; + + if (store::htonl(nAttrib) != e.m_nAttrib) + { + // Check access mode. + if (base::isWriteable()) + { + // Set new attributes. + e.m_nAttrib = store::htonl(nAttrib); + xNode->m_pData[i] = e; + + // Save modified NodePage. + eErrCode = saveObjectAt (aNode, aNode.location()); + } + else + { + // Access denied. + eErrCode = store_E_AccessViolation; + } + } + } + + // Obtain current attributes. + rAttrib = store::ntohl(e.m_nAttrib); + return eErrCode; +} + +/* + * link (insert 'Source' as hardlink to 'Destination'). + * Precond: initialized, writeable. + */ +storeError OStorePageManager::link ( + const OStorePageKey &rSrcKey, + const OStorePageKey &rDstKey) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Find 'Destination' NodePage and Index. + OStoreBTreeNodeObject aDstNode; + sal_uInt16 i = 0; + storeError eErrCode = find_lookup (aDstNode, i, rDstKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing 'Destination' entry. + PageHolderObject< page > xDstNode (aDstNode.get()); + entry e (xDstNode->m_pData[i]); + OStorePageLink aDstLink (e.m_aLink); + + // Find 'Source' NodePage and Index. + OStoreBTreeNodeObject aSrcNode; + eErrCode = m_aRoot.find_insert (aSrcNode, i, rSrcKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert 'Source' entry. + PageHolderObject< page > xSrcNode (aSrcNode.get()); + xSrcNode->insert (i + 1, entry (rSrcKey, aDstLink, STORE_ATTRIB_ISLINK)); + return saveObjectAt (aSrcNode, aSrcNode.location()); +} + +/* + * symlink (insert 'Source' DirectoryPage as symlink to 'Destination'). + * Precond: initialized, writeable. + */ +storeError OStorePageManager::symlink ( + const rtl_String *pSrcPath, + const rtl_String *pSrcName, + const OStorePageKey &rDstKey) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Check 'Source' parameter. + storeError eErrCode = store_E_InvalidParameter; + if (!(pSrcPath && pSrcName)) + return eErrCode; + + // Setup 'Source' page key. + OStorePageKey aSrcKey; + eErrCode = namei (pSrcPath, pSrcName, aSrcKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Find 'Source' NodePage and Index. + OStoreBTreeNodeObject aSrcNode; + sal_uInt16 i = 0; + eErrCode = m_aRoot.find_insert (aSrcNode, i, aSrcKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // Initialize directory page. + OStoreDirectoryPageObject aPage; + eErrCode = aPage.construct< inode >(base::allocator()); + if (eErrCode != store_E_None) + return eErrCode; + + // Setup as 'Source' directory page. + inode_holder_type xNode (aPage.get()); + aPage.key (aSrcKey); + memcpy ( + &(xNode->m_aNameBlock.m_pData[0]), + pSrcName->buffer, pSrcName->length); + + // Store 'Destination' page key. + OStorePageKey aDstKey (rDstKey); + memcpy (&(xNode->m_pData[0]), &aDstKey, sizeof(aDstKey)); + + // Mark 'Source' as symbolic link to 'Destination'. + aPage.attrib (STORE_ATTRIB_ISLINK); + aPage.dataLength (sal_uInt32(sizeof(aDstKey))); + + // Allocate and save 'Source' directory page. + eErrCode = base::allocate (aPage); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert 'Source' entry. + PageHolderObject< page > xSrcNode (aSrcNode.get()); + OStorePageLink aSrcLink (aPage.location()); + xSrcNode->insert (i + 1, entry(aSrcKey, aSrcLink)); + + // Save modified NodePage. + return saveObjectAt (aSrcNode, aSrcNode.location()); +} + +/* + * rename. + * Precond: initialized, writeable. + */ +storeError OStorePageManager::rename ( + const OStorePageKey &rSrcKey, + const rtl_String *pDstPath, + const rtl_String *pDstName) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Check 'Destination' parameter. + storeError eErrCode = store_E_InvalidParameter; + if (!(pDstPath && pDstName)) + return eErrCode; + + // Setup 'Destination' page key. + OStorePageKey aDstKey; + eErrCode = namei (pDstPath, pDstName, aDstKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Find 'Source' NodePage and Index. + OStoreBTreeNodeObject aSrcNode; + sal_uInt16 i = 0; + eErrCode = find_lookup (aSrcNode, i, rSrcKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing 'Source' entry. + PageHolderObject< page > xSrcNode (aSrcNode.get()); + entry e (xSrcNode->m_pData[i]); + + // Check for (not a) hardlink. + OStoreDirectoryPageObject aPage; + if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK)) + { + // Load directory page. + eErrCode = base::loadObjectAt (aPage, e.m_aLink.location()); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for directory. + if (aPage.attrib() & STORE_ATTRIB_ISDIR) + { + // Ugly, but necessary (backward compatibility). + aDstKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aDstKey.m_nLow), "/", 1)); + } + } + + // Let 'Source' entry be 'Destination' entry. + e.m_aKey = aDstKey; + + // Find 'Destination' NodePage and Index. + OStoreBTreeNodeObject aDstNode; + eErrCode = m_aRoot.find_insert (aDstNode, i, e.m_aKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert 'Destination' entry. + PageHolderObject< page > xDstNode (aDstNode.get()); + xDstNode->insert (i + 1, e); + + eErrCode = saveObjectAt (aDstNode, aDstNode.location()); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for (not a) hardlink. + if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK)) + { + // Modify 'Source' directory page. + inode_holder_type xNode (aPage.get()); + + // Setup 'Destination' NameBlock. + sal_Int32 nDstLen = pDstName->length; + memcpy ( + &(xNode->m_aNameBlock.m_pData[0]), + pDstName->buffer, pDstName->length); + memset ( + &(xNode->m_aNameBlock.m_pData[nDstLen]), + 0, STORE_MAXIMUM_NAMESIZE - nDstLen); + aPage.key (e.m_aKey); + + // Save directory page. + eErrCode = base::saveObjectAt (aPage, e.m_aLink.location()); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Remove 'Source' entry. + e.m_aKey = rSrcKey; + return remove_Impl (e); +} + +/* + * remove. + * Precond: initialized, writeable. + */ +storeError OStorePageManager::remove (const OStorePageKey &rKey) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Find NodePage and index. + OStoreBTreeNodeObject aNodePage; + sal_uInt16 i = 0; + storeError eErrCode = find_lookup (aNodePage, i, rKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing entry. + PageHolderObject< page > xNodePage (aNodePage.get()); + entry e (xNodePage->m_pData[i]); + + // Check for (not a) hardlink. + if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK)) + { + // Load directory page. + OStoreDirectoryPageObject aPage; + eErrCode = base::loadObjectAt (aPage, e.m_aLink.location()); + if (eErrCode != store_E_None) + return eErrCode; + + inode_holder_type xNode (aPage.get()); + + // Acquire page write access. + OStorePageDescriptor aDescr (xNode->m_aDescr); + eErrCode = base::acquirePage (aDescr, store_AccessReadWrite); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for symbolic link. + if (!(aPage.attrib() & STORE_ATTRIB_ISLINK)) + { + // Ordinary inode. Determine 'Data' scope. + inode::ChunkScope eScope = xNode->scope (aPage.dataLength()); + if (eScope == inode::SCOPE_EXTERNAL) + { + // External 'Data' scope. Truncate all external data pages. + eErrCode = aPage.truncate (0, *this); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Truncate internal data page. + memset (&(xNode->m_pData[0]), 0, xNode->capacity()); + aPage.dataLength (0); + } + + // Release page write access. + eErrCode = base::releasePage (aDescr, store_AccessReadWrite); + + // Release and free directory page. + OStorePageData aPageHead; + eErrCode = base::free (aPageHead, aPage.location()); + } + + // Remove entry. + return remove_Impl (e); +} + +/* + * RebuildContext. + */ +struct RebuildContext +{ + /** Representation. + */ + rtl::Reference<OStorePageBIOS> m_xBIOS; + OStorePageBIOS::ScanContext m_aCtx; + sal_uInt16 m_nPageSize; + + /** Construction. + */ + RebuildContext (void) + : m_xBIOS (new OStorePageBIOS()), + m_nPageSize (0) + {} + + /** initialize (PageBIOS and ScanContext). + */ + storeError initialize (ILockBytes *pLockBytes, sal_uInt32 nMagic = 0) + { + storeError eErrCode = store_E_InvalidParameter; + if (pLockBytes) + { + m_xBIOS->initialize (pLockBytes, store_AccessReadOnly, m_nPageSize); + eErrCode = m_xBIOS->scanBegin (m_aCtx, nMagic); + } + return eErrCode; + } + + /** initialize (ScanContext). + */ + storeError initialize (sal_uInt32 nMagic = 0) + { + return m_xBIOS->scanBegin (m_aCtx, nMagic); + } + + /** load (next ScanContext matching page). + */ + storeError load (OStorePageObject &rPage) + { + if (m_aCtx.isValid()) + return m_xBIOS->scanNext (m_aCtx, rPage); + else + return store_E_CantSeek; + } +}; + +/* + * rebuild. + * Precond: none. + */ +storeError OStorePageManager::rebuild ( + ILockBytes *pSrcLB, ILockBytes *pDstLB) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check arguments. + storeError eErrCode = store_E_InvalidParameter; + if (!(pSrcLB && pDstLB)) + return eErrCode; + + // Initialize 'Source' rebuild context. + RebuildContext aCtx; + eErrCode = aCtx.initialize (pSrcLB, STORE_MAGIC_DIRECTORYPAGE); + if (eErrCode != store_E_None) + return eErrCode; + rtl::Reference<OStorePageBIOS> xSrcBIOS (aCtx.m_xBIOS); + + // Initialize as 'Destination' with 'Source' page size. + eErrCode = self::initialize (pDstLB, store_AccessCreate, aCtx.m_nPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Pass One: Scan 'Source' directory pages. + { + // Scan 'Source' directory pages. + OStoreDirectoryPageObject aSrcPage; + while ((eErrCode = aCtx.load(aSrcPage)) == store_E_None) + { + OStoreDirectoryPageObject aDstPage; + eErrCode = aDstPage.construct< inode >(base::allocator()); + if (eErrCode != store_E_None) + break; + + inode_holder_type xSrcDir (aSrcPage.get()); + inode_holder_type xDstDir (aDstPage.get()); + + // Copy NameBlock @@@ OLD @@@ + memcpy (&(xDstDir->m_aNameBlock), &(xSrcDir->m_aNameBlock), sizeof(xSrcDir->m_aNameBlock)); + + // Obtain 'Source' data length. + sal_uInt32 nDataLen = aSrcPage.dataLength(); + if (nDataLen > 0) + { + // Copy internal data area @@@ OLD @@@ + memcpy (&(xDstDir->m_pData[0]), &(xSrcDir->m_pData[0]), xSrcDir->capacity()); + } + + // Insert 'Destination' directory page. + eErrCode = save_dirpage_Impl (aDstPage.key(), aDstPage); + if (eErrCode != store_E_None) + break; + + // Check for external data page scope. + if (xSrcDir->scope(nDataLen) != inode::SCOPE_INTERNAL) + { + // Initialize 'Destination' data page. + typedef OStoreDataPageData data; + PageHolderObject< data > xData; + if (!xData.construct(base::allocator())) + return store_E_OutOfMemory; + + // Determine data page count. + inode::ChunkDescriptor aDescr ( + nDataLen - xDstDir->capacity(), xData->capacity()); + + sal_uInt32 i, n = aDescr.m_nPage; + if (aDescr.m_nOffset) n += 1; + + // Copy data pages. + OStoreDataPageObject aData; + for (i = 0; i < n; i++) + { + // Read 'Source' data page. + osl::MutexGuard aSrcGuard (*xSrcBIOS); + + eErrCode = aSrcPage.read (i, aData, *xSrcBIOS); + if (eErrCode != store_E_None) + continue; + + // Write 'Destination' data page. @@@ READONLY @@@ + eErrCode = aDstPage.write (i, aData, *this); + } + } + + // Update 'Destination' directory page. + aDstPage.dataLength (nDataLen); + eErrCode = base::saveObjectAt (aDstPage, aDstPage.location()); + } + + // Save directory scan results. + flush(); + } + + // Pass Two: Scan 'Source' BTree nodes. + { + // Re-start 'Source' rebuild context. + aCtx.initialize (STORE_MAGIC_BTREENODE); + + // Scan 'Source' BTree nodes. + OStoreBTreeNodeObject aNode; + while ((eErrCode = aCtx.load(aNode)) == store_E_None) + { + // Check for leaf node. + PageHolderObject< page > xNode (aNode.get()); + if (xNode->depth() == 0) + { + sal_uInt16 i, n = xNode->usageCount(); + for (i = 0; i < n; i++) + { + entry e (xNode->m_pData[i]); + + // Check for Hard link. + if (e.m_nAttrib & STORE_ATTRIB_ISLINK) + { + // Load the hard link destination. + OStoreDirectoryPageObject aSrcPage; + eErrCode = xSrcBIOS->loadObjectAt (aSrcPage, e.m_aLink.location()); + if (eErrCode == store_E_None) + { + OStorePageKey aDstKey (aSrcPage.key()); + eErrCode = link (e.m_aKey, aDstKey); + } + e.m_nAttrib &= ~STORE_ATTRIB_ISLINK; + } + + if (e.m_nAttrib) + { + // Ordinary attributes. + sal_uInt32 nAttrib = 0; + eErrCode = attrib (e.m_aKey, 0, e.m_nAttrib, nAttrib); + } + } + } + } + + // Save BTree node scan results. + flush(); + } + + // Done. + return store_E_None; +} diff --git a/store/source/storpage.hxx b/store/source/storpage.hxx new file mode 100644 index 000000000000..938e5dd63bc9 --- /dev/null +++ b/store/source/storpage.hxx @@ -0,0 +1,229 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: storpage.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORPAGE_HXX_ +#define _STORE_STORPAGE_HXX_ "$Revision: 1.6.8.2 $" + +#include "sal/types.h" + +#include "object.hxx" +#include "lockbyte.hxx" + +#include "storbase.hxx" +#include "storbios.hxx" +#include "stortree.hxx" + +namespace store +{ + +struct OStoreDirectoryPageData; +class OStoreDirectoryPageObject; + +/*======================================================================== + * + * OStorePageManager interface. + * + *======================================================================*/ +class OStorePageManager : public store::OStorePageBIOS +{ +public: + /** Construction. + */ + OStorePageManager (void); + + /** Initialization (two-phase construction). + */ + virtual storeError initialize ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize); + + /** isValid. + * @return sal_True upon successful initialization, + * sal_False otherwise. + */ + inline sal_Bool isValid (void) const; + + /** DirectoryPage I/O (managed). + */ + static storeError namei ( + const rtl_String *pPath, + const rtl_String *pName, + OStorePageKey &rKey); + + storeError iget ( + OStoreDirectoryPageObject & rPage, // [out] + sal_uInt32 nAttrib, + const rtl_String * pPath, + const rtl_String * pName, + storeAccessMode eMode); + + storeError iterate ( + OStorePageKey & rKey, + OStorePageLink & rLink, + sal_uInt32 & rAttrib); + + /** attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)]. + * @see store_attrib() + */ + storeError attrib ( + const OStorePageKey &rKey, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 &rAttrib); + + /** link (insert Source Key as hardlink to Destination). + * @see store_link() + */ + storeError link ( + const OStorePageKey &rSrcKey, + const OStorePageKey &rDstKey); + + /** symlink (insert Source DirectoryPage as symlink to Destination). + * @see store_symlink() + */ + storeError symlink ( + const rtl_String *pSrcPath, + const rtl_String *pSrcName, + const OStorePageKey &rDstKey); + + /** rename. + * @see store_rename() + */ + storeError rename ( + const OStorePageKey &rSrcKey, + const rtl_String *pDstPath, + const rtl_String *pDstName); + + /** remove. + * @see store_remove() + */ + storeError remove ( + const OStorePageKey &rKey); + + /** rebuild (combines recover and compact from 'Src' to 'Dst'). + * @param pSrcLB [in] accessed readonly. + * @param pDstLB [in] truncated and accessed readwrite (as initialize()). + * @return store_E_None upon success. + * + * @see store_rebuildFile() + */ + storeError rebuild ( + ILockBytes *pSrcLB, + ILockBytes *pDstLB); + + /** IStoreHandle. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId); + +protected: + /** Destruction. + */ + virtual ~OStorePageManager (void); + +private: + /** Implementation. + */ + typedef OStorePageBIOS base; + typedef OStorePageManager self; + + typedef OStoreBTreeEntry entry; + typedef OStoreBTreeNodeData page; + typedef OStoreBTreeNodeObject node; + + typedef OStoreDirectoryPageData inode; + typedef PageHolderObject< inode > inode_holder_type; + + /** IStoreHandle TypeId. + */ + static const sal_uInt32 m_nTypeId; + + /** IStoreHandle query() template function specialization. + */ + friend OStorePageManager* + SAL_CALL query<> (IStoreHandle *pHandle, OStorePageManager*); + + /** Representation. + */ + OStoreBTreeRootObject m_aRoot; + + /** DirectoryPage I/O (managed). + */ + storeError load_dirpage_Impl ( // @@@ => private: iget() @@@ + const OStorePageKey &rKey, + OStoreDirectoryPageObject &rPage); + + storeError save_dirpage_Impl ( // @@@ => private: iget(), rebuild() @@@ + const OStorePageKey &rKey, + OStoreDirectoryPageObject &rPage); + + /** find_lookup (node page and index, w/o split). + */ + storeError find_lookup ( + OStoreBTreeNodeObject & rNode, + sal_uInt16 & rIndex, + OStorePageKey const & rKey); + + /** remove (possibly down from root). + */ + storeError remove_Impl (entry & rEntry); + + /** Not implemented. + */ + OStorePageManager (const OStorePageManager&); + OStorePageManager& operator= (const OStorePageManager&); +}; + +inline sal_Bool OStorePageManager::isValid (void) const +{ + return (base::isValid() /* @@@ NYI && (m_aRoot.is()) */); +} + +template<> inline OStorePageManager* +SAL_CALL query (IStoreHandle *pHandle, OStorePageManager*) +{ + if (pHandle && pHandle->isKindOf (OStorePageManager::m_nTypeId)) + { + // Handle is kind of OStorePageManager. + return static_cast<OStorePageManager*>(pHandle); + } + return 0; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORPAGE_HXX_ */ + diff --git a/store/source/stortree.cxx b/store/source/stortree.cxx new file mode 100644 index 000000000000..614b995aba72 --- /dev/null +++ b/store/source/stortree.cxx @@ -0,0 +1,688 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: stortree.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "stortree.hxx" + +#include "sal/types.h" +#include "osl/diagnose.h" + +#include "store/types.h" + +#include "storbase.hxx" +#include "storbios.hxx" + +using namespace store; + +/*======================================================================== + * + * OStoreBTreeNodeData implementation. + * + *======================================================================*/ +/* + * OStoreBTreeNodeData. + */ +OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize) + : OStorePageData (nPageSize) +{ + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); // usageCount(0) + self::m_aGuard.m_nMagic = store::htonl(0); // depth(0) + + sal_uInt16 const n = capacityCount(); + T const t; + + for (sal_uInt16 i = 1; i < n; i++) + m_pData[i] = t; +} + +/* + * find. + */ +sal_uInt16 OStoreBTreeNodeData::find (const T& t) const +{ + register sal_Int32 l = 0; + register sal_Int32 r = usageCount() - 1; + + while (l < r) + { + register sal_Int32 const m = ((l + r) >> 1); + + if (t.m_aKey == m_pData[m].m_aKey) + return ((sal_uInt16)(m)); + if (t.m_aKey < m_pData[m].m_aKey) + r = m - 1; + else + l = m + 1; + } + + sal_uInt16 const k = ((sal_uInt16)(r)); + if ((k < capacityCount()) && (t.m_aKey < m_pData[k].m_aKey)) + return(k - 1); + else + return(k); +} + +/* + * insert. + */ +void OStoreBTreeNodeData::insert (sal_uInt16 i, const T& t) +{ + sal_uInt16 const n = usageCount(); + sal_uInt16 const m = capacityCount(); + if ((n < m) && (i < m)) + { + // shift right. + memmove (&(m_pData[i + 1]), &(m_pData[i]), (n - i) * sizeof(T)); + + // insert. + m_pData[i] = t; + usageCount (n + 1); + } +} + +/* + * remove. + */ +void OStoreBTreeNodeData::remove (sal_uInt16 i) +{ + sal_uInt16 const n = usageCount(); + if (i < n) + { + // shift left. + memmove (&(m_pData[i]), &(m_pData[i + 1]), (n - i - 1) * sizeof(T)); + + // truncate. + m_pData[n - 1] = T(); + usageCount (n - 1); + } +} + +#if 0 /* NYI */ +/* + * merge (with right page). + */ +void OStoreBTreeNodeData::merge (const self& rPageR) +{ + sal_uInt16 const n = usageCount(); + sal_uInt16 const m = rPageR.usageCount(); + if ((n + m) <= capacityCount()) + { + memcpy (&(m_pData[n]), &(rPageR.m_pData[0]), m * sizeof(T)); + usageCount (n + m); + } +} +#endif + +/* + * split (left half copied from right half of left page). + */ +void OStoreBTreeNodeData::split (const self& rPageL) +{ + sal_uInt16 const h = capacityCount() / 2; + memcpy (&(m_pData[0]), &(rPageL.m_pData[h]), h * sizeof(T)); + truncate (h); +} + +/* + * truncate. + */ +void OStoreBTreeNodeData::truncate (sal_uInt16 n) +{ + sal_uInt16 const m = capacityCount(); + T const t; + + for (sal_uInt16 i = n; i < m; i++) + m_pData[i] = t; + usageCount (n); +} + +/*======================================================================== + * + * OStoreBTreeNodeObject implementation. + * + *======================================================================*/ +/* + * guard. + */ +storeError OStoreBTreeNodeObject::guard (sal_uInt32 nAddr) +{ + return PageHolderObject< page >::guard (m_xPage, nAddr); +} + +/* + * verify. + */ +storeError OStoreBTreeNodeObject::verify (sal_uInt32 nAddr) const +{ + return PageHolderObject< page >::verify (m_xPage, nAddr); +} + +/* + * split. + */ +storeError OStoreBTreeNodeObject::split ( + sal_uInt16 nIndexL, + PageHolderObject< page > & rxPageL, + OStorePageBIOS & rBIOS) +{ + PageHolderObject< page > xPage (m_xPage); + if (!xPage.is()) + return store_E_InvalidAccess; + + // Check left page usage. + if (!rxPageL.is()) + return store_E_InvalidAccess; + if (!rxPageL->querySplit()) + return store_E_None; + + // Save PageDescriptor. + OStorePageDescriptor aDescr (xPage->m_aDescr); + aDescr.m_nAddr = store::ntohl(aDescr.m_nAddr); + aDescr.m_nSize = store::ntohs(aDescr.m_nSize); + + // Acquire Lock. + storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); + if (eErrCode != store_E_None) + return eErrCode; + + // [Begin PageL Lock (NYI)] + + // Construct right page. + PageHolderObject< page > xPageR; + if (!xPageR.construct (rBIOS.allocator())) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return store_E_OutOfMemory; + } + + // Split right page off left page. + xPageR->split (*rxPageL); + xPageR->depth (rxPageL->depth()); + + // Allocate right page. + self aNodeR (xPageR.get()); + eErrCode = rBIOS.allocate (aNodeR); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Truncate left page. + rxPageL->truncate (rxPageL->capacityCount() / 2); + + // Save left page. + self aNodeL (rxPageL.get()); + eErrCode = rBIOS.saveObjectAt (aNodeL, aNodeL.location()); + if (eErrCode != store_E_None) + { + // Must not happen. + OSL_TRACE("OStoreBTreeNodeObject::split(): save() failed"); + + // Release Lock and Leave. + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // [End PageL Lock (NYI)] + + // Insert right page. + OStorePageLink aLink (xPageR->location()); + xPage->insert (nIndexL + 1, T(xPageR->m_pData[0].m_aKey, aLink)); + + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + { + // Must not happen. + OSL_TRACE("OStoreBTreeNodeObject::split(): save() failed"); + + // Release Lock and Leave. + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Release Lock and Leave. + return rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); +} + +/* + * remove (down to leaf node, recursive). + */ +storeError OStoreBTreeNodeObject::remove ( + sal_uInt16 nIndexL, + OStoreBTreeEntry & rEntryL, + OStorePageBIOS & rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Save PageDescriptor. + OStorePageDescriptor aDescr (rPage.m_aDescr); + aDescr.m_nAddr = store::ntohl(aDescr.m_nAddr); + aDescr.m_nSize = store::ntohs(aDescr.m_nSize); + + // Acquire Lock. + storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Check depth. + if (rPage.depth()) + { + // Check link entry. + T const aEntryL (rPage.m_pData[nIndexL]); + if (!(rEntryL.compare (aEntryL) == T::COMPARE_EQUAL)) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return store_E_InvalidAccess; + } + + // Load link node. + self aNodeL; + eErrCode = rBIOS.loadObjectAt (aNodeL, aEntryL.m_aLink.location()); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Recurse: remove from link node. + eErrCode = aNodeL.remove (0, rEntryL, rBIOS); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Check resulting link node usage. + PageHolderObject< page > xPageL (aNodeL.get()); + if (xPageL->usageCount() == 0) + { + // Free empty link node. + OStorePageData aPageHead; + eErrCode = rBIOS.free (aPageHead, xPageL->location()); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Remove index. + rPage.remove (nIndexL); + touch(); + } + else + { +#if 0 /* NYI */ + // Check for right sibling. + sal_uInt16 const nIndexR = nIndexL + 1; + if (nIndexR < rPage.usageCount()) + { + // Load right link node. + self aNodeR; + eErrCode = rBIOS.loadObjectAt (aNodeR, rPage.m_pData[nIndexR].m_aLink.location()); + if (eErrCode == store_E_None) + { + if (rPageL.queryMerge (rPageR)) + { + rPageL.merge (rPageR); + + eErrCode = rBIOS.free (aPageHead, rPageR.location()); + } + } + } +#endif /* NYI */ + + // Relink. + rPage.m_pData[nIndexL].m_aKey = xPageL->m_pData[0].m_aKey; + touch(); + } + } + else + { + // Check leaf entry. + if (!(rEntryL.compare (rPage.m_pData[nIndexL]) == T::COMPARE_EQUAL)) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return store_E_NotExists; + } + + // Save leaf entry. + rEntryL = rPage.m_pData[nIndexL]; + + // Remove leaf index. + rPage.remove (nIndexL); + touch(); + } + + // Check for modified node. + if (dirty()) + { + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + { + // Must not happen. + OSL_TRACE("OStoreBTreeNodeObject::remove(): save() failed"); + + // Release Lock and Leave. + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + } + + // Release Lock and Leave. + return rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); +} + +/*======================================================================== + * + * OStoreBTreeRootObject implementation. + * + *======================================================================*/ +/* + * testInvariant. + * Precond: root node page loaded. + */ +bool OStoreBTreeRootObject::testInvariant (char const * message) +{ + OSL_PRECOND(m_xPage.get() != 0, "OStoreBTreeRootObject::testInvariant(): Null pointer"); + bool result = ((m_xPage->location() - m_xPage->size()) == 0); + OSL_POSTCOND(result, message); (void) message; + return result; +} + +/* + * loadOrCreate. + */ +storeError OStoreBTreeRootObject::loadOrCreate ( + sal_uInt32 nAddr, + OStorePageBIOS & rBIOS) +{ + storeError eErrCode = rBIOS.loadObjectAt (*this, nAddr); + if (eErrCode != store_E_NotExists) + return eErrCode; + + eErrCode = construct<page>(rBIOS.allocator()); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = rBIOS.allocate (*this); + if (eErrCode != store_E_None) + return eErrCode; + + // Notify caller of the creation. + (void) testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave"); + return store_E_Pending; +} + +/* + * change. + */ +storeError OStoreBTreeRootObject::change ( + PageHolderObject< page > & rxPageL, + OStorePageBIOS & rBIOS) +{ + PageHolderObject< page > xPage (m_xPage); + (void) testInvariant("OStoreBTreeRootObject::change(): enter"); + + // Save PageDescriptor. + OStorePageDescriptor aDescr (xPage->m_aDescr); + aDescr.m_nAddr = store::ntohl(aDescr.m_nAddr); + aDescr.m_nSize = store::ntohs(aDescr.m_nSize); + + // Save root location. + sal_uInt32 const nRootAddr = xPage->location(); + + // Acquire Lock. + storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Construct new root. + if (!rxPageL.construct (rBIOS.allocator())) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return store_E_OutOfMemory; + } + + // Save this as prev root. + eErrCode = rBIOS.allocate (*this); + if (eErrCode != store_E_None) + { + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return store_E_OutOfMemory; + } + + // Setup new root. + rxPageL->depth (xPage->depth() + 1); + rxPageL->m_pData[0] = xPage->m_pData[0]; + rxPageL->m_pData[0].m_aLink = xPage->location(); + rxPageL->usageCount(1); + + // Change root. + rxPageL.swap (xPage); + { + PageHolder tmp (xPage.get()); + tmp.swap (m_xPage); + } + + // Save this as new root. + eErrCode = rBIOS.saveObjectAt (*this, nRootAddr); + if (eErrCode != store_E_None) + { + // Must not happen. + OSL_TRACE("OStoreBTreeRootObject::change(): save() failed"); + + // Release Lock and Leave. + rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); + return eErrCode; + } + + // Flush for robustness. + (void) rBIOS.flush(); + + // Done. Release Lock and Leave. + (void) testInvariant("OStoreBTreeRootObject::change(): leave"); + return rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); +} + +/* + * find_lookup (w/o split()). + * Precond: root node page loaded. + */ +storeError OStoreBTreeRootObject::find_lookup ( + OStoreBTreeNodeObject & rNode, // [out] + sal_uInt16 & rIndex, // [out] + OStorePageKey const & rKey, + OStorePageBIOS & rBIOS) +{ + // Init node w/ root page. + (void) testInvariant("OStoreBTreeRootObject::find_lookup(): enter"); + { + PageHolder tmp (m_xPage); + tmp.swap (rNode.get()); + } + + // Setup BTree entry. + T const entry (rKey); + + // Check current page. + PageHolderObject< page > xPage (rNode.get()); + for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >()) + { + // Find next page. + page const & rPage = (*xPage); + sal_uInt16 const i = rPage.find(entry); + sal_uInt16 const n = rPage.usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Check address. + sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location(); + if (nAddr == STORE_PAGE_NULL) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Load next page. + storeError eErrCode = rBIOS.loadObjectAt (rNode, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Find index. + page const & rPage = (*xPage); + rIndex = rPage.find(entry); + if (!(rIndex < rPage.usageCount())) + return store_E_NotExists; + + // Compare entry. + T::CompareResult eResult = entry.compare(rPage.m_pData[rIndex]); + OSL_POSTCOND(eResult != T::COMPARE_LESS, "store::BTreeRoot::find_lookup(): sort error"); + if (eResult == T::COMPARE_LESS) + return store_E_Unknown; + + // Greater or Equal. + (void) testInvariant("OStoreBTreeRootObject::find_lookup(): leave"); + return store_E_None; +} + +/* + * find_insert (possibly with split()). + * Precond: root node page loaded. + */ +storeError OStoreBTreeRootObject::find_insert ( + OStoreBTreeNodeObject & rNode, // [out] + sal_uInt16 & rIndex, // [out] + OStorePageKey const & rKey, + OStorePageBIOS & rBIOS) +{ + (void) testInvariant("OStoreBTreeRootObject::find_insert(): enter"); + + // Check for RootNode split. + PageHolderObject< page > xRoot (m_xPage); + if (xRoot->querySplit()) + { + PageHolderObject< page > xPageL; + + // Change root. + storeError eErrCode = change (xPageL, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Split left page (prev root). + eErrCode = split (0, xPageL, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Init node w/ root page. + { + PageHolder tmp (m_xPage); + tmp.swap (rNode.get()); + } + + // Setup BTree entry. + T const entry (rKey); + + // Check current Page. + PageHolderObject< page > xPage (rNode.get()); + for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >()) + { + // Find next page. + page const & rPage = (*xPage); + sal_uInt16 const i = rPage.find (entry); + sal_uInt16 const n = rPage.usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Check address. + sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location(); + if (nAddr == STORE_PAGE_NULL) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Load next page. + OStoreBTreeNodeObject aNext; + storeError eErrCode = rBIOS.loadObjectAt (aNext, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for next node split. + PageHolderObject< page > xNext (aNext.get()); + if (xNext->querySplit()) + { + // Split next node. + eErrCode = rNode.split (i, xNext, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Restart. + continue; + } + + // Let next page be current. + PageHolder tmp (aNext.get()); + tmp.swap (rNode.get()); + } + + // Find index. + page const & rPage = (*xPage); + rIndex = rPage.find(entry); + if (rIndex < rPage.usageCount()) + { + // Compare entry. + T::CompareResult result = entry.compare (rPage.m_pData[rIndex]); + OSL_POSTCOND(result != T::COMPARE_LESS, "store::BTreeRoot::find_insert(): sort error"); + if (result == T::COMPARE_LESS) + return store_E_Unknown; + + if (result == T::COMPARE_EQUAL) + return store_E_AlreadyExists; + } + + // Greater or not (yet) existing. + (void) testInvariant("OStoreBTreeRootObject::find_insert(): leave"); + return store_E_None; +} diff --git a/store/source/stortree.hxx b/store/source/stortree.hxx new file mode 100644 index 000000000000..9aa5da92cfda --- /dev/null +++ b/store/source/stortree.hxx @@ -0,0 +1,348 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: stortree.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORTREE_HXX +#define _STORE_STORTREE_HXX "$Revision: 1.6.8.2 $" + +#include "sal/types.h" + +#include "store/types.h" + +#include "storbase.hxx" + +namespace store +{ + +class OStorePageBIOS; + +/*======================================================================== + * + * OStoreBTreeEntry. + * + *======================================================================*/ +struct OStoreBTreeEntry +{ + typedef OStorePageKey K; + typedef OStorePageLink L; + + /** Representation. + */ + K m_aKey; + L m_aLink; + sal_uInt32 m_nAttrib; + + /** Construction. + */ + explicit OStoreBTreeEntry ( + K const & rKey = K(), + L const & rLink = L(), + sal_uInt32 nAttrib = 0) + : m_aKey (rKey), + m_aLink (rLink), + m_nAttrib (store::htonl(nAttrib)) + {} + + OStoreBTreeEntry (const OStoreBTreeEntry & rhs) + : m_aKey (rhs.m_aKey), + m_aLink (rhs.m_aLink), + m_nAttrib (rhs.m_nAttrib) + {} + + OStoreBTreeEntry& operator= (const OStoreBTreeEntry & rhs) + { + m_aKey = rhs.m_aKey; + m_aLink = rhs.m_aLink; + m_nAttrib = rhs.m_nAttrib; + return *this; + } + + /** Comparison. + */ + enum CompareResult + { + COMPARE_LESS = -1, + COMPARE_EQUAL = 0, + COMPARE_GREATER = 1 + }; + + CompareResult compare (const OStoreBTreeEntry& rOther) const + { + if (m_aKey < rOther.m_aKey) + return COMPARE_LESS; + else if (m_aKey == rOther.m_aKey) + return COMPARE_EQUAL; + else + return COMPARE_GREATER; + } +}; + +/*======================================================================== + * + * OStoreBTreeNodeData. + * + *======================================================================*/ +#define STORE_MAGIC_BTREENODE sal_uInt32(0x58190322) + +struct OStoreBTreeNodeData : public store::OStorePageData +{ + typedef OStorePageData base; + typedef OStoreBTreeNodeData self; + + typedef OStorePageGuard G; + typedef OStoreBTreeEntry T; + + /** Representation. + */ + G m_aGuard; + T m_pData[1]; + + /** type. + */ + static const sal_uInt32 theTypeId = STORE_MAGIC_BTREENODE; + + /** theSize. + */ + static const size_t theSize = sizeof(G); + static const sal_uInt16 thePageSize = base::theSize + self::theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= self::thePageSize); + + /** capacity. + */ + sal_uInt16 capacity (void) const + { + return (store::ntohs(base::m_aDescr.m_nSize) - self::thePageSize); + } + + /** capacityCount (must be even). + */ + sal_uInt16 capacityCount (void) const + { + return sal_uInt16(capacity() / sizeof(T)); + } + + /** usage. + */ + sal_uInt16 usage (void) const + { + return (store::ntohs(base::m_aDescr.m_nUsed) - self::thePageSize); + } + + /** usageCount. + */ + sal_uInt16 usageCount (void) const + { + return sal_uInt16(usage() / sizeof(T)); + } + void usageCount (sal_uInt16 nCount) + { + size_t const nBytes = self::thePageSize + nCount * sizeof(T); + base::m_aDescr.m_nUsed = store::htons(sal::static_int_cast< sal_uInt16 >(nBytes)); + } + + /** Construction. + */ + explicit OStoreBTreeNodeData (sal_uInt16 nPageSize = self::thePageSize); + + /** guard (external representation). + */ + void guard() + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, m_pData, capacity()); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, m_pData, capacity()); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } + + /** depth. + */ + sal_uInt32 depth (void) const + { + return store::ntohl(self::m_aGuard.m_nMagic); + } + void depth (sal_uInt32 nDepth) + { + self::m_aGuard.m_nMagic = store::htonl(nDepth); + } + + /** queryMerge. + */ + sal_Bool queryMerge (const self &rPageR) const + { + return ((usageCount() + rPageR.usageCount()) <= capacityCount()); + } + + /** querySplit. + */ + sal_Bool querySplit (void) const + { + return (!(usageCount() < capacityCount())); + } + + /** Operation. + */ + sal_uInt16 find (const T& t) const; + void insert (sal_uInt16 i, const T& t); + void remove (sal_uInt16 i); + +#if 0 /* NYI */ + /** merge (with right page). + */ + void merge (const self& rPageR); +#endif + + /** split (left half copied from right half of left page). + */ + void split (const self& rPageL); + + /** truncate (to n elements). + */ + void truncate (sal_uInt16 n); +}; + +/*======================================================================== + * + * OStoreBTreeNodeObject. + * + *======================================================================*/ +class OStoreBTreeNodeObject : public store::OStorePageObject +{ + typedef OStorePageObject base; + typedef OStoreBTreeNodeObject self; + typedef OStoreBTreeNodeData page; + + typedef OStoreBTreeEntry T; + +public: + /** Construction. + */ + explicit OStoreBTreeNodeObject (PageHolder const & rxPage = PageHolder()) + : OStorePageObject (rxPage) + {} + + /** External representation. + */ + virtual storeError guard (sal_uInt32 nAddr); + virtual storeError verify (sal_uInt32 nAddr) const; + + /** split. + * + * @param rxPageL [inout] left child to be split + */ + storeError split ( + sal_uInt16 nIndexL, + PageHolderObject< page > & rxPageL, + OStorePageBIOS & rBIOS); + + /** remove (down to leaf node, recursive). + */ + storeError remove ( + sal_uInt16 nIndexL, + OStoreBTreeEntry & rEntryL, + OStorePageBIOS & rBIOS); +}; + +/*======================================================================== + * + * OStoreBTreeRootObject. + * + *======================================================================*/ +class OStoreBTreeRootObject : public store::OStoreBTreeNodeObject +{ + typedef OStoreBTreeNodeObject base; + typedef OStoreBTreeNodeData page; + + typedef OStoreBTreeEntry T; + +public: + /** Construction. + */ + explicit OStoreBTreeRootObject (PageHolder const & rxPage = PageHolder()) + : OStoreBTreeNodeObject (rxPage) + {} + + storeError loadOrCreate ( + sal_uInt32 nAddr, + OStorePageBIOS & rBIOS); + + /** find_lookup (w/o split()). + * Precond: root node page loaded. + */ + storeError find_lookup ( + OStoreBTreeNodeObject & rNode, // [out] + sal_uInt16 & rIndex, // [out] + OStorePageKey const & rKey, + OStorePageBIOS & rBIOS); + + /** find_insert (possibly with split()). + * Precond: root node page loaded. + */ + storeError find_insert ( + OStoreBTreeNodeObject & rNode, + sal_uInt16 & rIndex, + OStorePageKey const & rKey, + OStorePageBIOS & rBIOS); + +private: + /** testInvariant. + * Precond: root node page loaded. + */ + bool testInvariant (char const * message); + + /** change (Root). + * + * @param rxPageL [out] prev. root (needs split) + */ + storeError change ( + PageHolderObject< page > & rxPageL, + OStorePageBIOS & rBIOS); +}; + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORTREE_HXX */ diff --git a/store/util/makefile.mk b/store/util/makefile.mk new file mode 100644 index 000000000000..57733e5ca2a9 --- /dev/null +++ b/store/util/makefile.mk @@ -0,0 +1,83 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.24 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=.. + +PRJNAME=store +TARGET=store +TARGETTYPE=CUI + +USE_LDUMP2=TRUE +USE_DEFFILE=TRUE + +NO_BSYMBOLIC=TRUE +NO_DEFAULT_STL=TRUE + +UNIXVERSIONNAMES=UDK + +# --- Settings --- + +.INCLUDE : settings.mk + +# --- Debug-Library --- + +.IF "$(debug)" != "" + +LIB1TARGET= $(LB)$/$(TARGET)dbg.lib +LIB1ARCHIV= $(LB)$/lib$(TARGET)dbg.a +LIB1FILES= $(LB)$/store.lib + +.ENDIF # debug + +# --- Shared-Library --- + +SHL1TARGET= $(TARGET) +SHL1IMPLIB= istore + +SHL1VERSIONMAP= $(TARGET).map + +SHL1STDLIBS= $(SALLIB) + +SHL1DEF= $(MISC)$/$(SHL1TARGET).def +SHL1LIBS= $(SLB)$/store.lib +SHL1RPATH= URELIB + +# --- Def-File --- + +DEF1NAME= $(SHL1TARGET) +DEF1DES=Store + +# --- Targets --- + +.INCLUDE : target.mk + + + diff --git a/store/util/store.map b/store/util/store.map new file mode 100644 index 000000000000..51fc36048b96 --- /dev/null +++ b/store/util/store.map @@ -0,0 +1,31 @@ +UDK_3_0_0 { + global: + store_acquireHandle; + store_attrib; + store_closeDirectory; + store_closeFile; + store_closeStream; + store_createMemoryFile; + store_findFirst; + store_findNext; + store_flushFile; + store_flushStream; + store_getFileRefererCount; + store_getFileSize; + store_getStreamSize; + store_link; + store_openDirectory; + store_openFile; + store_openStream; + store_readStream; + store_rebuildFile; + store_releaseHandle; + store_remove; + store_rename; + store_setStreamSize; + store_symlink; + store_writeStream; + local: + *; +}; + diff --git a/store/util/store.xml b/store/util/store.xml new file mode 100644 index 000000000000..0cd8cbef9d2c --- /dev/null +++ b/store/util/store.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE module-description PUBLIC "-//StarOffice//DTD ComponentDescription 1.0//EN" "module-description.dtd"> +<module-description xmlns:xlink="http://www.w3.org/1999/xlink"> + <module-name> store </module-name> + <project-build-dependency> sal </project-build-dependency> + <runtime-module-dependency> sal </runtime-module-dependency> +</module-description> diff --git a/store/version.mk b/store/version.mk new file mode 100644 index 000000000000..e9171328da44 --- /dev/null +++ b/store/version.mk @@ -0,0 +1,44 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: version.mk,v $ +# +# $Revision: 1.3 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +# target +STORE_TARGET=store + +# the major +STORE_MAJOR=2 +# the minor +STORE_MINOR=0 +# the micro +STORE_MICRO=0 + +# this is a c++ compatible library +STORE_CPP=0 + diff --git a/store/workben/makefile.mk b/store/workben/makefile.mk new file mode 100644 index 000000000000..4b58d26409a0 --- /dev/null +++ b/store/workben/makefile.mk @@ -0,0 +1,110 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.6 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=.. + +PRJNAME=store +TARGET=workben + +LIBTARGET=NO +TARGETTYPE=CUI +NO_DEFAULT_STL=TRUE + +# --- Settings --- + +.INCLUDE : settings.mk + +.IF "$(STORELIB)" == "" +.IF "$(GUI)" == "UNX" +STORELIB= -lstore +.ELSE # unx +.IF "$(GUI)$(COM)"=="WNTGCC" +STORELIB= -lstore$(UDK_MAJOR) +.ELSE +STORELIB= $(LB)$/istore.lib +.ENDIF +.ENDIF # unx +.ENDIF # storelib + +.IF "$(GUI)" == "UNX" +STOREDBGLIB= $(LB)$/libstoredbg.a +.ELSE # unx +.IF "$(GUI)$(COM)"=="WNTGCC" +STOREDBGLIB= $(LB)$/libstoredbg.a +.ELSE +STOREDBGLIB= $(LB)$/storedbg.lib +.ENDIF +.ENDIF # unx + +CFLAGS+= -I..$/source + +# --- Files --- + +OBJFILES= \ + $(OBJ)$/t_leak.obj \ + $(OBJ)$/t_file.obj \ + $(OBJ)$/t_page.obj \ + $(OBJ)$/t_base.obj \ + $(OBJ)$/t_store.obj + +APP1TARGET= t_file +APP1OBJS= $(OBJ)$/t_file.obj +APP1STDLIBS= $(STOREDBGLIB) +APP1STDLIBS+= $(SALLIB) +APP1DEPN= $(STOREDBGLIB) + +APP2TARGET= t_page +APP2OBJS= $(OBJ)$/t_page.obj +APP2STDLIBS= $(STOREDBGLIB) +APP2STDLIBS+= $(SALLIB) +APP2DEPN= $(STOREDBGLIB) + +APP3TARGET= t_base +APP3OBJS= $(OBJ)$/t_base.obj +APP3STDLIBS= $(STOREDBGLIB) +APP3STDLIBS+= $(SALLIB) +APP3DEPN= $(STOREDBGLIB) + +APP4TARGET= t_store +APP4OBJS= $(OBJ)$/t_store.obj +APP4STDLIBS= $(STORELIB) +APP4STDLIBS+= $(SALLIB) +APP4DEPN= $(SLB)$/store.lib +APP4RPATH= UREBIN + + APP5TARGET= t_leak + APP5OBJS= $(OBJ)$/t_leak.obj + APP5STDLIBS+= $(SALLIB) + +# --- Targets --- + +.INCLUDE : target.mk + diff --git a/store/workben/t_base.cxx b/store/workben/t_base.cxx new file mode 100644 index 000000000000..593736e4d57b --- /dev/null +++ b/store/workben/t_base.cxx @@ -0,0 +1,385 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: t_base.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "sal/types.h" +#include "osl/diagnose.h" +#include "osl/thread.h" +#include "rtl/memory.h" +#include "rtl/ustring.hxx" + +#include "object.hxx" +#include "storbase.hxx" +#include "storbios.hxx" +#include "lockbyte.hxx" + +using namespace store; + +#define TEST_PAGESIZE 1024 + +/*======================================================================== + * + * OTestObject. + * + *======================================================================*/ +class OTestObject : public store::OStoreObject +{ +public: + OTestObject (void); + + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId); + +protected: + virtual ~OTestObject (void); +}; + +OTestObject::OTestObject (void) +{ +} + +OTestObject::~OTestObject (void) +{ +} + +sal_Bool SAL_CALL OTestObject::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == 42); +} + +namespace store +{ +static OTestObject* SAL_CALL query (IStoreHandle *pHandle, OTestObject*) +{ + if (pHandle && pHandle->isKindOf (42)) + return static_cast<OTestObject*>(pHandle); + else + return 0; +} +} + +/*======================================================================== + * + * OTestBIOS. + * + *======================================================================*/ +namespace store +{ + +class OTestBIOS : public store::OStorePageBIOS +{ + typedef store::OStorePageBIOS base; + + friend OTestBIOS* SAL_CALL query<> (IStoreHandle * pHandle, OTestBIOS *); + +public: + OTestBIOS (void); + + virtual storeError initialize ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize); + + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId); + +protected: + virtual ~OTestBIOS (void); +}; + +} // namespace store + +OTestBIOS::OTestBIOS (void) +{ +} + +OTestBIOS::~OTestBIOS (void) +{ +} + +sal_Bool SAL_CALL OTestBIOS::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == 4242); +} + +storeError OTestBIOS::initialize ( + ILockBytes *pLockBytes, storeAccessMode eAccessMode, sal_uInt16 & rnPageSize) +{ + return base::initialize (pLockBytes, eAccessMode, rnPageSize); +} + +namespace store +{ +template<> OTestBIOS* SAL_CALL query (IStoreHandle *pHandle, OTestBIOS*) +{ + if (pHandle && pHandle->isKindOf (4242)) + return static_cast<OTestBIOS*>(pHandle); + else + return 0; +} +} + +/*======================================================================== + * + * __store_test_handle. + * + *======================================================================*/ +static void __store_test_handle (void* Handle) +{ + IStoreHandle *pHandle = static_cast<IStoreHandle*>(Handle); + if (pHandle) + { + pHandle->acquire(); + pHandle->isKindOf (42); + pHandle->release(); + } + + OTestObject *pObj = query (pHandle, static_cast<OTestObject*>(0)); + if (pObj) + { + pObj->acquire(); + pObj->isKindOf (42); + pObj->release(); + } +} + +/*======================================================================== + * + * unicode. + * + *======================================================================*/ +static void __store_string_newFromUnicode_WithLength ( + rtl_String **newString, const sal_Unicode *value, sal_Int32 length) +{ + rtl_uString2String ( + newString, + value, length, + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS); +} + +#if 0 /* UNSUSED */ +static void __store_string_newFromUnicode ( + rtl_String **newString, const rtl_uString *value) +{ + __store_string_newFromUnicode_WithLength ( + newString, value->buffer, value->length); +} +#endif /* UNUSED */ + +static void __store_string_newFromUnicode ( + rtl_String **newString, const sal_Unicode *value) +{ + __store_string_newFromUnicode_WithLength ( + newString, value, rtl_ustr_getLength (value)); +} + +static storeError __store_namei ( + const sal_Unicode *pszPath, + const sal_Unicode *pszName, + OStorePageKey &rKey) +{ + rtl::OString aName ( + pszName, rtl_ustr_getLength (pszName), RTL_TEXTENCODING_UTF8); + + rtl_String *pszNameA = 0; + __store_string_newFromUnicode (&pszNameA, pszName); + + storeError eErrCode = store_E_NameTooLong; + if (pszNameA->length < sal_Int32(sizeof(sal_Char[STORE_MAXIMUM_NAMESIZE]))) + { + rtl_String *pszPathA = 0; + __store_string_newFromUnicode (&pszPathA, pszPath); + + rKey.m_nLow = rtl_crc32 (0, pszNameA->buffer, pszNameA->length); + rKey.m_nHigh = rtl_crc32 (0, pszPathA->buffer, pszPathA->length); + + rtl_string_release (pszPathA); + eErrCode = store_E_None; + } + + rtl_string_release (pszNameA); + return eErrCode; +} + +static sal_Size __store_convertTextToUnicode ( + rtl_TextToUnicodeConverter hConvert, + const sal_Char *pszText, sal_Size nTextLen, + sal_Unicode *pBuffer, sal_Size nBuffer) +{ + sal_uInt32 nInfo = 0; + sal_Size nSrcLen = 0; + + sal_Int32 nDstLen = rtl_convertTextToUnicode ( + hConvert, 0, + pszText, nTextLen, + pBuffer, nBuffer, + OSTRING_TO_OUSTRING_CVTFLAGS, + &nInfo, &nSrcLen); + + pBuffer[nDstLen] = 0; + return nDstLen; +} + +struct MyFindData +{ + sal_Unicode m_pszName[STORE_MAXIMUM_NAMESIZE]; + sal_Int32 m_nLength; + sal_uInt32 m_nAttrib; + sal_uInt32 m_nSize; + sal_uInt32 m_nReserved; +}; + +static void __store_testUnicode (const sal_Char *pszFilename) +{ + // ... + rtl_TextToUnicodeConverter hConvert; + hConvert = rtl_createTextToUnicodeConverter (RTL_TEXTENCODING_UTF8); + + MyFindData it; + rtl_zeroMemory (&it, sizeof(it)); + + sal_Int32 n = rtl_str_getLength (pszFilename); + n = __store_convertTextToUnicode ( + hConvert, pszFilename, n, + it.m_pszName, STORE_MAXIMUM_NAMESIZE - 1); + if (it.m_nLength > n) + rtl_zeroMemory ( + &it.m_pszName[n], ((it.m_nLength - n) * sizeof(sal_Unicode))); + it.m_nLength = n; + + rtl_destroyTextToUnicodeConverter (hConvert); + + // ... + rtl_String *pszFileA = NULL; + rtl_uString *pszFileW = NULL; + + // rtl_uString_newFromAscii (&pszFileW, pszFilename); + + // ... + rtl_string_newFromStr (&pszFileA, pszFilename); + + rtl_string2UString ( + &pszFileW, + pszFileA->buffer, pszFileA->length, + RTL_TEXTENCODING_MS_1252, + OSTRING_TO_OUSTRING_CVTFLAGS); + + rtl_string_release (pszFileA); + + // ... + OStorePageKey aKey; + __store_namei (pszFileW->buffer, pszFileW->buffer, aKey); + + // ... + rtl_uString2String ( + &pszFileA, + pszFileW->buffer, pszFileW->length, + RTL_TEXTENCODING_UTF8, + OUSTRING_TO_OSTRING_CVTFLAGS); + + rtl_uString_release (pszFileW); + + // ... + rtl_string_release (pszFileA); +} + +/*======================================================================== + * + * main. + * + *======================================================================*/ +int SAL_CALL main (int argc, char **argv) +{ + OSL_PRECOND(argc > 1, "t_base: error: insufficient number of arguments."); + if (argc < 2) + return 0; + + __store_testUnicode (argv[1]); + + rtl::Reference<ILockBytes> xLockBytes; + + rtl::OUString aFilename ( + argv[1], rtl_str_getLength(argv[1]), + osl_getThreadTextEncoding()); + + storeError eErrCode = FileLockBytes_createInstance ( + xLockBytes, aFilename.pData, store_AccessReadCreate); + if (eErrCode != store_E_None) + return eErrCode; + + + rtl::Reference<OTestObject> xObject (new OTestObject()); + __store_test_handle (&*xObject); + + rtl::Reference<OTestBIOS> xBIOS (new OTestBIOS()); + __store_test_handle (&*xBIOS); + + + if (!xBIOS.is()) + return 0; + + sal_uInt16 nPageSize = TEST_PAGESIZE; + eErrCode = xBIOS->initialize (&*xLockBytes, store_AccessReadWrite, nPageSize); + if (eErrCode != store_E_None) + { + // Check reason. + if (eErrCode != store_E_NotExists) + return eErrCode; + + // Create. + eErrCode = xBIOS->initialize (&*xLockBytes, store_AccessReadCreate, nPageSize); + if (eErrCode != store_E_None) + return eErrCode; + } + xLockBytes.clear(); + + sal_Char pBuffer[TEST_PAGESIZE]; + rtl_zeroMemory (pBuffer, sizeof (pBuffer)); + rtl_copyMemory (pBuffer, argv[0], rtl_str_getLength(argv[0]) + 1); + + eErrCode = xBIOS->acquireLock (TEST_PAGESIZE, sizeof(pBuffer)); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = xBIOS->write (TEST_PAGESIZE, pBuffer, sizeof (pBuffer)); + if (eErrCode != store_E_None) + { + xBIOS->releaseLock (TEST_PAGESIZE, sizeof(pBuffer)); + return eErrCode; + } + + eErrCode = xBIOS->releaseLock (TEST_PAGESIZE, sizeof(pBuffer)); + if (eErrCode != store_E_None) + return eErrCode; + + xBIOS.clear(); + return 0; +} diff --git a/store/workben/t_file.cxx b/store/workben/t_file.cxx new file mode 100644 index 000000000000..d4feb25651eb --- /dev/null +++ b/store/workben/t_file.cxx @@ -0,0 +1,247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: t_file.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "sal/types.h" +#include "osl/thread.h" +#include "rtl/ustring.hxx" + +#include "lockbyte.hxx" + +#ifndef INCLUDED_STDIO_H +#include <stdio.h> +#define INCLUDED_STDIO_H +#endif + +#include "osl/file.h" +#include "osl/process.h" + +using namespace store; + +#define TEST_PAGESIZE 16384 + +/*======================================================================== + * + * main. + * + *======================================================================*/ +int SAL_CALL main (int argc, char **argv) +{ + storeError eErrCode = store_E_None; + rtl::Reference<ILockBytes> xLockBytes; + + if (argc > 1) + { + rtl::OUString aFilename ( + argv[1], rtl_str_getLength(argv[1]), + osl_getThreadTextEncoding()); + +#if 0 /* EXP */ + oslFileError result; + rtl::OUString aPath; + + result = osl_getFileURLFromSystemPath(aFilename.pData, &(aPath.pData)); + if (result != osl_File_E_None) + { + // not SystemPath, assume FileUrl. + aPath = aFilename; + } + if (rtl_ustr_ascii_shortenedCompare_WithLength(aPath.pData->buffer, aPath.pData->length, "file://", 7) != 0) + { + // not FileUrl, assume relative path. + rtl::OUString aBase; + (void) osl_getProcessWorkingDir (&(aBase.pData)); + + // absolute FileUrl. + (void) osl_getAbsoluteFileURL(aBase.pData, aPath.pData, &(aPath.pData)); + } + aFilename = aPath; +#endif /* EXP */ + + eErrCode = FileLockBytes_createInstance ( + xLockBytes, aFilename.pData, store_AccessReadWrite); + if (eErrCode != store_E_None) + { + // Check reason. + if (eErrCode != store_E_NotExists) + { + fprintf (stderr, "t_file: create() error: %d\n", eErrCode); + return eErrCode; + } + + // Create. + eErrCode = FileLockBytes_createInstance ( + xLockBytes, aFilename.pData, store_AccessReadCreate); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: create() error: %d\n", eErrCode); + return eErrCode; + } + } + fprintf (stdout, "t_file: using FileLockBytes(\"%s\") implementation.\n", argv[1]); + } + else + { + eErrCode = MemoryLockBytes_createInstance (xLockBytes); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: create() error: %d\n", eErrCode); + return eErrCode; + } + fprintf (stdout, "t_file: using MemoryLockBytes implementation.\n"); + } + + rtl::Reference< PageData::Allocator > xAllocator; + eErrCode = xLockBytes->initialize (xAllocator, TEST_PAGESIZE); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: initialize() error: %d\n", eErrCode); + return eErrCode; + } + + sal_Char buffer[TEST_PAGESIZE]; + rtl_fillMemory (buffer, sizeof(buffer), sal_uInt8('B')); + + sal_uInt32 i, k; + for (k = 0; k < 4; k++) + { + sal_uInt32 index = k * TEST_PAGESIZE / 4; + buffer[index] = 'A'; + } + + for (i = 0; i < 256; i++) + { + sal_uInt32 offset = i * TEST_PAGESIZE; + eErrCode = xLockBytes->setSize (offset + TEST_PAGESIZE); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: setSize() error: %d\n", eErrCode); + return eErrCode; + } + + for (k = 0; k < 4; k++) + { + sal_uInt32 magic = i * 4 + k; + if (magic) + { + sal_uInt32 verify = 0; + eErrCode = xLockBytes->readAt ( + 0, &verify, sizeof(verify)); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: readAt() error: %d\n", eErrCode); + return eErrCode; + } + if (verify != magic) + { + // Failure. + fprintf (stderr, "Expected %ld read %ld\n", (unsigned long)(magic), (unsigned long)(verify)); + } + } + + sal_uInt32 index = k * TEST_PAGESIZE / 4; + eErrCode = xLockBytes->writeAt ( + offset + index, &(buffer[index]), TEST_PAGESIZE / 4); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: writeAt() error: %d\n", eErrCode); + return eErrCode; + } + + magic += 1; + eErrCode = xLockBytes->writeAt ( + 0, &magic, sizeof(magic)); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: writeAt() error: %d\n", eErrCode); + return eErrCode; + } + } + } + + eErrCode = xLockBytes->flush(); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: flush() error: %d\n", eErrCode); + return eErrCode; + } + + sal_Char verify[TEST_PAGESIZE]; + for (i = 0; i < 256; i++) + { + sal_uInt32 offset = i * TEST_PAGESIZE; + + eErrCode = xLockBytes->readAt (offset, verify, TEST_PAGESIZE); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: readAt() error: %d\n", eErrCode); + return eErrCode; + } + + sal_uInt32 index = 0; + if (offset == 0) + { + sal_uInt32 magic = 256 * 4; + if (rtl_compareMemory (&verify[index], &magic, sizeof(magic))) + { + // Failure. + fprintf (stderr, "t_file: Unexpected value at 0x00000000\n"); + } + index += 4; + } + if (rtl_compareMemory ( + &verify[index], &buffer[index], TEST_PAGESIZE - index)) + { + // Failure. + fprintf (stderr, "t_file: Unexpected block at 0x%08x\n", (unsigned)(offset)); + } + } + + for (i = 0; i < 256; i++) + { + PageHolder xPage; + sal_uInt32 offset = i * TEST_PAGESIZE; + + eErrCode = xLockBytes->readPageAt (xPage, offset); + if (eErrCode != store_E_None) + { + fprintf (stderr, "t_file: readPageAt() error: %d\n", eErrCode); + return eErrCode; + } + + PageData * page = xPage.get(); + (void)page; // UNUSED + } + + xLockBytes.clear(); + return 0; +} diff --git a/store/workben/t_leak.cxx b/store/workben/t_leak.cxx new file mode 100644 index 000000000000..d4d7b8a840e1 --- /dev/null +++ b/store/workben/t_leak.cxx @@ -0,0 +1,19 @@ +/* + * t_leak.cxx + */ + +#include "sal/main.h" +#include "osl/process.h" +#include "osl/thread.h" + + int main (int /*argc*/, char ** /*argv*/) +//SAL_IMPLEMENT_MAIN() +{ + rtl_Locale * pLocale = 0; + osl_getProcessLocale (&pLocale); +#if 0 + rtl_TextEncoding te = osl_getThreadTextEncoding(); + (void) te; +#endif + return 0; +} diff --git a/store/workben/t_page.cxx b/store/workben/t_page.cxx new file mode 100644 index 000000000000..a0645f00bc58 --- /dev/null +++ b/store/workben/t_page.cxx @@ -0,0 +1,1574 @@ +/* + * t_page.cxx + */ + +#include "osl/diagnose.h" +#include "rtl/alloc.h" +#include "rtl/ref.hxx" + +#include "storbase.hxx" + +#include "osl/file.h" +#include "rtl/ustring.hxx" + +/*======================================================================== + * + * OTest... + * + *======================================================================*/ + +template< class T > void swap (T & lhs, T & rhs) +{ + T tmp = rhs; rhs = lhs; lhs = tmp; +} + +/*======================================================================*/ + +class SharedCount +{ + long * m_pCount; + + class Allocator + { + rtl_cache_type * m_cache; + + public: + static Allocator & get(); + + long * alloc() + { + return static_cast<long*>(rtl_cache_alloc (m_cache)); + } + void free (long * pCount) + { + rtl_cache_free (m_cache, pCount); + } + + protected: + Allocator(); + ~Allocator(); + }; + +public: + SharedCount() + : m_pCount(Allocator::get().alloc()) + { + if (m_pCount != 0) (*m_pCount) = 1; + } + + ~SharedCount() + { + if (m_pCount != 0) + { + long new_count = --(*m_pCount); + if (new_count == 0) + Allocator::get().free(m_pCount); + } + } + + bool operator== (long count) const + { + return (m_pCount != 0) ? *m_pCount == count : false; + } + + friend void swap<> (SharedCount & lhs, SharedCount & rhs); // nothrow + + SharedCount (SharedCount const & rhs); // nothrow + SharedCount & operator= (SharedCount const & rhs); // nothrow +}; + +template<> +inline void swap (SharedCount & lhs, SharedCount & rhs) // nothrow +{ + swap<long*>(lhs.m_pCount, rhs.m_pCount); +} + +SharedCount::SharedCount (SharedCount const & rhs) // nothrow + : m_pCount (rhs.m_pCount) +{ + if (m_pCount != 0) ++(*m_pCount); +} + +SharedCount & +SharedCount::operator= (SharedCount const & rhs) // nothrow +{ + SharedCount tmp(rhs); + swap<SharedCount>(tmp, *this); + return *this; +} + +SharedCount::Allocator & +SharedCount::Allocator::get() +{ + static Allocator g_aSharedCountAllocator; + return g_aSharedCountAllocator; +} + +SharedCount::Allocator::Allocator() +{ + m_cache = rtl_cache_create ( + "store_shared_count_cache", + sizeof(long), + 0, // objalign + 0, // constructor + 0, // destructor + 0, // reclaim + 0, // userarg + 0, // default source + 0 // flags + ); +} + +SharedCount::Allocator::~Allocator() +{ + rtl_cache_destroy (m_cache), m_cache = 0; +} + +/*======================================================================*/ + +#if 0 /* OLD */ + +typedef store::OStorePageData PageData; + +#else /* NEW */ + +#if defined(OSL_BIGENDIAN) +#define STORE_DWORD(dword) OSL_SWAPDWORD((dword)) +#else +#define STORE_DWORD(dword) (dword) +#endif + +struct PageData +{ + typedef store::OStorePageGuard G; + typedef store::OStorePageDescriptor D; + typedef store::OStorePageLink L; + + /** Representation. + */ + G m_aGuard; + D m_aDescr; + L m_aMarked; + L m_aUnused; + + /** theSize. + */ + static const size_t theSize = sizeof(G) + sizeof(D) + 2 * sizeof(L); + static const sal_uInt16 thePageSize = theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize); + + /** type. + */ + sal_uInt32 type() const { return m_aGuard.m_nMagic; /* @@@ */ } + + /** offset. + */ + sal_uInt32 offset() const { return m_aDescr.m_nAddr; /* @@@ */ } + void offset (sal_uInt32 nOffset) { m_aDescr.m_nAddr = nOffset; } + + /** size. + */ + sal_uInt16 size() const { return m_aDescr.m_nSize; /* @@@ */ } + + /** Allocation. + */ + class Allocator : public rtl::IReference + { + public: + template< class T > T * construct() + { + void * page = 0; sal_uInt16 size = 0; + if (allocate (&page, &size)) + { + return new(page) T(size); + } + return 0; + } + + virtual bool allocate (void ** ppPage, sal_uInt16 * pnSize) = 0; + virtual void deallocate (void * pPage) = 0; + }; + + static void * operator new (size_t, void * p) { return p; } + static void operator delete (void *, void *) {} + + /** Construction. + */ + explicit PageData (sal_uInt16 nPageSize = thePageSize) + : m_aDescr (STORE_PAGE_NULL, nPageSize, thePageSize) + {} + + /** ... + */ + void guard() + {} + + storeError verify() const + { + return store_E_None; + } +}; + +#endif /* NEW */ + +class IPageAllocator +{ +public: + virtual void deallocate (void * p) = 0; +}; + +class PageAllocator +{ + rtl_cache_type * m_cache; + SharedCount m_refcount; + +public: + PageAllocator() + : m_cache(0), m_refcount() + {} + + ~PageAllocator() + { + // NYI + if (m_refcount == 1) + { + } + } + + friend void swap<>(PageAllocator & lhs, PageAllocator & rhs); + + PageAllocator (PageAllocator const & rhs); + PageAllocator & operator= (PageAllocator const & rhs); +}; + +template<> +inline void swap (PageAllocator & lhs, PageAllocator & rhs) +{ + swap<rtl_cache_type*>(lhs.m_cache, rhs.m_cache); + swap<SharedCount>(lhs.m_refcount, rhs.m_refcount); +} + +PageAllocator::PageAllocator (PageAllocator const & rhs) + : m_cache (rhs.m_cache), + m_refcount (rhs.m_refcount) +{ +} + +PageAllocator & +PageAllocator::operator= (PageAllocator const & rhs) +{ + PageAllocator tmp (rhs); + swap<PageAllocator>(tmp, *this); + return *this; +} + +/*======================================================================*/ + +class PageHolder +{ + SharedCount m_refcount; + PageData * m_pagedata; + + typedef rtl::Reference< PageData::Allocator > allocator_type; + allocator_type m_allocator; + +public: + explicit PageHolder (PageData * pagedata = 0, allocator_type const & allocator = allocator_type()) + : m_refcount (), + m_pagedata (pagedata), + m_allocator(allocator) + {} + + ~PageHolder() + { + if ((m_refcount == 1) && (m_pagedata != 0) && m_allocator.is()) + { + // free pagedata. + m_allocator->deallocate (m_pagedata); + } + } + + PageData * get() { return m_pagedata; } + PageData const * get() const { return m_pagedata; } + + PageData * operator->() { return m_pagedata; } + PageData const * operator->() const { return m_pagedata; } + + friend void swap<> (PageHolder & lhs, PageHolder & rhs); // nothrow + + PageHolder (PageHolder const & rhs); // nothrow + PageHolder & operator= (PageHolder const & rhs); // nothrow +}; + +template<> +inline void swap (PageHolder & lhs, PageHolder & rhs) // nothrow +{ + swap<SharedCount>(lhs.m_refcount, rhs.m_refcount); + swap<PageData*>(lhs.m_pagedata, rhs.m_pagedata); + swap<PageHolder::allocator_type>(lhs.m_allocator, rhs.m_allocator); +} + +PageHolder::PageHolder (PageHolder const & rhs) // nothrow + : m_refcount (rhs.m_refcount), + m_pagedata (rhs.m_pagedata), + m_allocator(rhs.m_allocator) +{} + +PageHolder & +PageHolder::operator= (PageHolder const & rhs) // nothrow +{ + PageHolder tmp (rhs); + swap<PageHolder>(tmp, *this); + return *this; +} + +/*======================================================================*/ + +template< class T > +class PageHolderObject +{ +protected: + /** Representation. + */ + PageHolder m_xPage; + + /** Checked cast. + */ + template< class U > + static bool isA (PageData const * p) + { + return ((p != 0) && (p->type() == U::theTypeId)); + } + + template< class U > + static U * dynamic_page_cast (PageData * p) + { + return isA<U>(p) ? static_cast<U*>(p) : 0; + } + + template< class U > + static U const * dynamic_page_cast (PageData const * p) + { + return isA<U>(p) ? static_cast<U const *>(p) : 0; + } + +public: + static PageHolderObject<T> construct (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + PageHolderObject<T> tmp; + if (rxAllocator.is()) + { + PageHolder xPage (rxAllocator->construct<T>(), rxAllocator); + store::swap<PageHolder>(tmp.m_xPage, xPage); + } + return tmp; + } + + explicit PageHolderObject (PageHolder const & rxPage = PageHolder()) + : m_xPage (rxPage) + {} + + void swap (PageHolderObject<T> & rhs) + { + store::swap<PageHolder>(m_xPage, rhs.m_xPage); + } + + PageHolderObject (PageHolderObject<T> const & rhs) + : m_xPage (rhs.m_xPage) + { + } + + PageHolderObject<T> & operator= (PageHolderObject<T> const & rhs) + { + PageHolderObject<T> tmp (rhs); + this->swap(tmp); + return *this; + } + + T * operator->() + { + T * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator->(): Null pointer"); + return pImpl; + } + T const * operator->() const + { + T const * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator->(): Null pointer"); + return pImpl; + } + + T & operator*() + { + T * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return *pImpl; + } + T const & operator*() const + { + T const * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return *pImpl; + } + + static storeError guard (PageHolder & rxPage) + { + T * pImpl = dynamic_page_cast<T>(rxPage.get()); + if (pImpl != 0) + { pImpl->guard(); return store_E_None; } + else if (rxPage.get() != 0) + return store_E_WrongVersion; + else + return store_E_InvalidAccess; + } + static storeError verify (PageHolder const & rxPage) + { + T const * pImpl = dynamic_page_cast<T>(rxPage.get()); + if (pImpl != 0) + return pImpl->verify(); + else if (rxPage.get() != 0) + return store_E_WrongVersion; + else + return store_E_InvalidAccess; + } +}; + +/*======================================================================*/ + +class PageObject +{ +public: + explicit PageObject (PageHolder const & rxPage = PageHolder()) + : m_xPage (rxPage) + {} + + virtual ~PageObject(); + + PageHolder & get() { return m_xPage; } + PageHolder const & get() const { return m_xPage; } + + PageData * operator->() + { + PageData * pImpl = m_xPage.get(); + OSL_PRECOND(pImpl != 0, "store::PageObject::operator->(): Null pointer"); + return pImpl; + } + PageData & operator*() + { + PageData * pImpl = m_xPage.get(); + OSL_PRECOND(pImpl != 0, "store::PageObject::operator*(): Null pointer"); + return *pImpl; + } + + virtual void guard(); + virtual storeError verify() const; + +protected: + PageHolder m_xPage; +}; + +PageObject::~PageObject() +{} +void PageObject::guard() +{ + PageData * p = m_xPage.get(); + p->guard(); +} +storeError PageObject::verify() const +{ + PageData const * p = m_xPage.get(); + return p->verify(); +} + +/*======================================================================*/ + +template< class T > +T * dynamic_page_cast (PageData * pagedata) +{ + if ((pagedata != 0) && (pagedata->type() == T::theTypeId)) + return static_cast<T*>(pagedata); + return 0; +} + +template< class T > +T * dynamic_page_cast (PageData const * pagedata) +{ + if ((pagedata != 0) && (pagedata->type() == T::theTypeId)) + return static_cast<T*>(pagedata); + return 0; +} + +/*======================================================================*/ + +class TestBIOS +{ +public: + storeError loadPageAt (PageHolder & rPage, storeError (*pfnVerify)(PageHolder const &)) + { + return (pfnVerify)(rPage); + } + + storeError allocate (PageHolder & rxPage, ...) + { + // NYI: PageObject.save(nAddr, *this); + (void)rxPage; // NYI + return store_E_Unknown; // NYI + } + + storeError loadAt (PageHolder & rPage, sal_uInt32 nOffset) + { + (void)rPage; // NYI + (void)nOffset; // NYI + return store_E_Unknown; // NYI + } + storeError saveAt (PageHolder const & rPage, sal_uInt32 nOffset) + { + (void)rPage; // NYI + (void)nOffset; // NYI + return store_E_Unknown; // NYI + } + + template< class T > + storeError save (PageHolder & rxPage, sal_uInt32 nOffset) + { + storeError result = PageHolderObject<T>::guard (rxPage); + if (result != store_E_None) + return result; + return saveAt (rxPage, nOffset); + } + + storeError lookupAt (PageHolder & rPage, sal_uInt32 nOffset) + { + (void)rPage; // NYI + (void)nOffset; // NYI + return store_E_NotExists; + } + storeError replaceAt (PageHolder const & rPage, sal_uInt32 nOffset) + { + (void)rPage; // NYI + (void)nOffset; // NYI + return store_E_None; + } +}; + +struct TestDataV1 : public PageData +{ + static const sal_uInt32 theTypeId = 6 * 9; +}; +struct TestData : public PageData +{ + typedef PageData base; + typedef TestData self; + + static const sal_uInt32 theTypeId = 42; + + void guard() + { + base::guard(); + // self::m_aGuard = ...; + } + storeError verify() const + { + storeError result = base::verify(); + if (result != store_E_None) + return result; + if (!(base::type() == self::theTypeId)) + return store_E_WrongVersion; + return store_E_None; + } + + storeError dwim() const + { + return store_E_None; + } +}; +class TestObject : public PageObject +{ + typedef PageObject base; + +public: + + void dwim() + { + PageHolderObject< TestData > xPage (m_xPage); + xPage->guard(); + } + + virtual void guard() + { + TestData * pagedata = dynamic_page_cast< TestData >(m_xPage.get()); + if (pagedata != 0) + {} + } + virtual storeError verify() const + { + storeError result = base::verify(); + if (result != store_E_None) + return result; + + TestData const * pagedata = dynamic_page_cast< TestData const >(m_xPage.get()); + if (!pagedata) + return store_E_WrongVersion; + + return pagedata->verify(); + } + + static storeError verify (PageHolder const & rPage) + { + return PageHolderObject< TestData >::verify (rPage); + } + + storeError loadAt (sal_uInt32 nOffset, TestBIOS & rBIOS) + { + storeError result = rBIOS.lookupAt (m_xPage, nOffset); // cache lookup + if (result == store_E_NotExists) + { + result = rBIOS.loadAt (m_xPage, nOffset); + if (result != store_E_None) + return result; + + result = PageHolderObject< TestData >::verify (m_xPage); + if (result != store_E_None) + return result; + + result = rBIOS.replaceAt (m_xPage, nOffset); // cache insert + } + return result; + } + storeError saveAt (sal_uInt32 nOffset, TestBIOS & rBIOS) + { + if (!m_xPage.get()) + return store_E_InvalidAccess; + m_xPage->m_aDescr.m_nAddr = store::htonl(nOffset); // m_xPage->location (nOffset); + + storeError result = PageHolderObject< TestData >::guard (m_xPage); + if (result != store_E_None) + return result; + + result = rBIOS.saveAt (m_xPage, nOffset); + if (result != store_E_None) + return result; + + return rBIOS.replaceAt (m_xPage, nOffset); // cache update + } +}; + +class TestObjectV2 : public PageHolderObject< TestData > +{ + typedef PageHolderObject< TestData > base; + +public: + storeError saveAt (sal_uInt32 nOffset, TestBIOS & rBIOS) + { + m_xPage->offset(nOffset); + + storeError result = PageHolderObject< TestData >::guard (m_xPage); + if (result != store_E_None) + return result; + + result = rBIOS.saveAt (m_xPage, nOffset); + if (result != store_E_None) + return result; + + return rBIOS.replaceAt (m_xPage, nOffset); + } +#if 1 + storeError dwim() const + { + TestData const * pImpl1 = operator->(); + + PageHolderObject< TestData > xImpl (m_xPage); + + TestData const * pImpl2 = &*xImpl; + OSL_ASSERT(pImpl1 == pImpl2); + + return xImpl->dwim(); + } +#endif +}; + +class TestClient +{ +public: + void dwim(TestBIOS & rBIOS) + { + TestObject aObj; + + rBIOS.loadPageAt(aObj.get(), aObj.verify); + rBIOS.loadPageAt(aObj.get(), TestObject::verify); + rBIOS.loadPageAt(aObj.get(), PageHolderObject<TestData>::verify); + + aObj.loadAt (1024, rBIOS); + + TestObjectV2 aObj2; + aObj2.dwim(); + aObj2->dwim(); + } +}; + +/*======================================================================*/ +#if 0 /* NYI */ +BIOS::load (PageObject & rPage, sal_uInt32 nOffset) +{ + result = m_xCache->readPageAt (rPage.get(), nOffset); + if (result == NotExists) + { + result = m_xLockBytes->readPageAt (rPage.get(), nOffset); + if (result != None) + return result; + + result = rPage.verify(); + if (result != None) + return result; + + result = m_xCache->writePageAt (rPage.get(), nOffset); + } + return result; +} +BIOS::save (PageObject & rPage, sal_uInt32 nOffset) +{ + rPage.guard(); + result = m_xLockBytes->writePageAt (rPage.get(), nOffset); + if (result != None) + return result; + + return m_xCache->writePageAt (rPage.get(), nOffset); +} +BIOS::init (rxLockBytes, eAccessMode, nPageSize) +{ + SuperPage super; + if (eAccessMode == store_AccessCreate) + { + sal_uInt16 pagesize = nPageSize; + if ((STORE_MINIMUM_PAGESIZE > pagesize) || (pagesize > STORE_MAXIMUM_PAGESIZE)) + return store_E_InvalidParameter; + + pagesize = ((pagesize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1)); + rxLockBytes->init (pagesize); + + super = allocator->construct<SuperPage>(); + super->guard(); + + rxLockBytes->writeAt (0, super, super->size()); + + } + if (eAccessMode != store_AccessCreate) + { + rxLockBytes->readAt (0, &super, super::theSize); + + super.verify(); + } + if (eErrCode != store_E_NotExists) + + +} +#endif /* NYI */ +/*======================================================================*/ + +#if 0 /* NYI */ +class PageCache +{ + std::set<const sal_uInt32, PageObject> m_pages; +public: + storeError readPageAt (PageObject & rPage, sal_uInt32 nOffset); + storeError writePageAt (PageObject const & rPage, sal_uInt32 nOffset); +}; +#endif /* NYI */ + +/*======================================================================*/ + +class IPageAllocator; +class IPageAccess +{ +public: + virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) = 0; + virtual IPageAllocator & getAllocator () = 0; + +public: + storeError readPageAt (PageHolder & rPage, sal_uInt32 nOffset) + { + return readPageAt_Impl (rPage, nOffset); + } + storeError writePageAt (PageHolder const & rPage, sal_uInt32 nOffset) + { + // [SECURITY:ValInput] + PageData const * pagedata = rPage.get(); + OSL_PRECOND(!(pagedata == 0), "invalid Page"); + if (pagedata == 0) + return store_E_InvalidParameter; + + sal_uInt32 const offset = pagedata->offset(); + OSL_PRECOND(!(nOffset != offset), "inconsistent Offset"); + if (nOffset != offset) + return store_E_InvalidParameter; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::IPageAccess::writePageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return writePageAt_Impl (rPage, nOffset); + } + + storeError peekAt (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) + { + // [SECURITY:ValInput] + sal_uInt8 * dst_lo = static_cast<sal_uInt8*>(pBuffer); + if (!(dst_lo != 0)) + return store_E_InvalidParameter; + + sal_uInt8 * dst_hi = dst_lo + nBytes; + if (!(dst_lo < dst_hi)) + return (dst_lo > dst_hi) ? store_E_InvalidParameter : store_E_None; + + sal_uInt64 const dst_size = nOffset + nBytes; + if (dst_size > SAL_MAX_UINT32) + return store_E_CantSeek; + + return peekAt_Impl (nOffset, dst_lo, (dst_hi - dst_lo)); + } + + storeError pokeAt (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) + { + // [SECURITY:ValInput] + sal_uInt8 const * src_lo = static_cast<sal_uInt8 const*>(pBuffer); + if (!(src_lo != 0)) + return store_E_InvalidParameter; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if (!(src_lo < src_hi)) + return (src_lo > src_hi) ? store_E_InvalidParameter : store_E_None; + + sal_uInt64 const dst_size = nOffset + nBytes; + if (dst_size > SAL_MAX_UINT32) + return store_E_CantSeek; + + return pokeAt_Impl (nOffset, src_lo, (src_hi - src_lo)); + } + + storeError getSize (sal_uInt32 & rnSize) + { + rnSize = 0; + return getSize_Impl (rnSize); + } + + storeError setSize (sal_uInt32 nSize) + { + return setSize_Impl (nSize); + } + +private: + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) = 0; + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) = 0; + + virtual storeError peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) = 0; + virtual storeError pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) = 0; + + virtual storeError getSize_Impl (sal_uInt32 & rnSize) = 0; + virtual storeError setSize_Impl (sal_uInt32 nSize) = 0; +}; + +/*======================================================================*/ + +template< class T > struct ResourceHolder +{ + typedef typename T::destructor_type destructor_type; + + T m_value; + + explicit ResourceHolder (T const & value = T()) : m_value (value) {} + ~ResourceHolder() { reset(); } + + T & get() { return m_value; } + T const & get() const { return m_value; } + + void set (T const & value) { m_value = value; } + void reset (T const & value = T()) + { + T tmp (m_value); + if (tmp != value) + destructor_type()(tmp); + set (value); + } + T release() + { + T tmp (m_value); + set (T()); + return tmp; + } + + ResourceHolder (ResourceHolder & rhs) + { + set (rhs.release()); + } + ResourceHolder & operator= (ResourceHolder & rhs) + { + reset (rhs.release()); + return *this; + } +}; + +struct FileHandle +{ + oslFileHandle m_handle; + + FileHandle() : m_handle(0) {} + + operator oslFileHandle() { return m_handle; } + + bool operator != (FileHandle const & rhs) + { + return (m_handle != rhs.m_handle); + } + + oslFileError initialize (rtl_uString * pFilename, sal_uInt32 nFlags) + { + // Verify arguments. + if (!pFilename || !nFlags) + return osl_File_E_INVAL; + + // Convert into FileUrl. + rtl::OUString aFileUrl; + if (osl_getFileURLFromSystemPath (pFilename, &(aFileUrl.pData)) != osl_File_E_None) + { + // Not system path. Maybe a file url, already. + rtl_uString_assign (&(aFileUrl.pData), pFilename); + } + + // Acquire handle. + return osl_openFile (aFileUrl.pData, &m_handle, nFlags); + } + + struct CloseFile + { + void operator()(FileHandle & rFile) const + { + if (rFile.m_handle != 0) + { + // Release handle. + (void) osl_closeFile (rFile.m_handle); + rFile.m_handle = 0; + } + } + }; + typedef CloseFile destructor_type; +}; + +struct FileMapping +{ + void * m_pAddr; + sal_uInt64 m_uSize; + + FileMapping() : m_pAddr(0), m_uSize(0) {} + + bool operator != (FileMapping const & rhs) const + { + return ((m_pAddr != rhs.m_pAddr) || (m_uSize != rhs.m_uSize)); + } + + oslFileError initialize (oslFileHandle hFile) + { + // Determine mapping size. + oslFileError result = osl_getFileSize (hFile, &m_uSize); + if (result != osl_File_E_None) + return result; + if (m_uSize > SAL_MAX_UINT32) + return osl_File_E_OVERFLOW; + + // Acquire mapping. + return osl_mapFile (hFile, &m_pAddr, m_uSize, 0, 0); + } + + struct UnmapFile + { + void operator ()(FileMapping & rMapping) const + { + if ((rMapping.m_pAddr != 0) && (rMapping.m_uSize != 0)) + { + // Release mapping. + (void) osl_unmapFile (rMapping.m_pAddr, rMapping.m_uSize); + rMapping.m_pAddr = 0, rMapping.m_uSize = 0; + } + } + }; + typedef UnmapFile destructor_type; +}; + +/*======================================================================*/ + +class FilePageAccess : public IPageAccess +{ + oslFileHandle m_hFile; + +public: + static storeError ERROR_FROM_NATIVE (oslFileError eErrno); + static sal_uInt32 MODE_TO_NATIVE (storeAccessMode eMode); + +public: + explicit FilePageAccess (oslFileHandle hFile = 0) : m_hFile (hFile) {} + virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize); + +private: + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); + + /* see @ OFileLockBytes */ + virtual storeError peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); + virtual storeError pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); + + virtual storeError getSize_Impl (sal_uInt32 & rnSize); + virtual storeError setSize_Impl (sal_uInt32 nSize); + +protected: + virtual ~FilePageAccess(); + +private: + /** Not implemented. + */ + FilePageAccess (FilePageAccess const &); + FilePageAccess & operator= (FilePageAccess const &); +}; + +storeError FilePageAccess::initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) +{ + (void) eAccessMode; // UNUSED + (void) nPageSize; // UNUSED + return store_E_Unknown; // NYI +} +FilePageAccess::~FilePageAccess() +{ + if (m_hFile != 0) + (void) osl_closeFile (m_hFile); +} +storeError FilePageAccess::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) +{ + PageHolder page (0/*allocate()*/); /* @@@ construct w/ deallocator argument @@@ */ + if (!page.get()) + return store_E_OutOfMemory; + + swap<PageHolder>(page, rPage); + return peekAt (nOffset, rPage.get(), 0/*size*/); +} +storeError FilePageAccess::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) +{ + return pokeAt (nOffset, rPage.get(), 0/*size*/); +} +storeError FilePageAccess::peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt64 nDone = 0; + oslFileError result = osl_readFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone); + if (result != osl_File_E_None) + return ERROR_FROM_NATIVE(result); + if (nDone != nBytes) + return (nDone != 0) ? store_E_CantRead : store_E_NotExists; + return store_E_None; +} +storeError FilePageAccess::pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt64 nDone = 0; + oslFileError result = osl_writeFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone); + if (result != osl_File_E_None) + return ERROR_FROM_NATIVE(result); + if (nDone != nBytes) + return store_E_CantWrite; + return store_E_None; +} +storeError FilePageAccess::getSize_Impl (sal_uInt32 & rnSize) +{ + sal_uInt64 uSize = 0; + oslFileError result = osl_getFileSize (m_hFile, &uSize); + if (result != osl_File_E_None) + return ERROR_FROM_NATIVE(result); + if (uSize > SAL_MAX_UINT32) + return store_E_CantSeek; + + rnSize = sal::static_int_cast<sal_uInt32>(uSize); + return store_E_None; +} +storeError FilePageAccess::setSize_Impl (sal_uInt32 nSize) +{ + oslFileError result = osl_setFileSize (m_hFile, nSize); + if (result != osl_File_E_None) + return ERROR_FROM_NATIVE(result); + return store_E_None; +} +storeError FilePageAccess::ERROR_FROM_NATIVE (oslFileError eErrno) +{ + switch (eErrno) + { + case osl_File_E_None: + return store_E_None; + + case osl_File_E_NOENT: + return store_E_NotExists; + + case osl_File_E_ACCES: + case osl_File_E_PERM: + return store_E_AccessViolation; + + case osl_File_E_AGAIN: + case osl_File_E_DEADLK: + return store_E_LockingViolation; + + case osl_File_E_BADF: + return store_E_InvalidHandle; + + case osl_File_E_INVAL: + return store_E_InvalidParameter; + + case osl_File_E_NOSPC: + return store_E_OutOfSpace; + + case osl_File_E_OVERFLOW: + return store_E_CantSeek; + + default: + return store_E_Unknown; + } +} +sal_uInt32 FilePageAccess::MODE_TO_NATIVE(storeAccessMode eAccessMode) +{ + sal_uInt32 nMode = 0; + switch (eAccessMode) + { + case store_AccessCreate: + case store_AccessReadCreate: + nMode |= osl_File_OpenFlag_Create; + // fall through + case store_AccessReadWrite: + nMode |= osl_File_OpenFlag_Write; + // fall through + case store_AccessReadOnly: + nMode |= osl_File_OpenFlag_Read; + break; + default: + OSL_PRECOND(0, "store::FilePageAccess: unknown storeAccessMode"); + } + return nMode; +} + +/*===*/ + +class MemoryPageAccess : public IPageAccess +{ + /** Representation. + */ + sal_uInt8 * m_pData; + sal_uInt32 m_nSize; + + /** Callback function to release Representation. + */ + typedef void (*destructor_type)(sal_uInt8 * pData, sal_uInt32 nSize); + destructor_type m_destructor; + + /** Default destructor callback. + */ + static void freeMemory (sal_uInt8 * pData, sal_uInt32 nSize); + +public: + MemoryPageAccess() + : m_pData (0), m_nSize (0), m_destructor (MemoryPageAccess::freeMemory) + {} + MemoryPageAccess (sal_uInt8 * pData, sal_uInt32 nSize, destructor_type destructor = MemoryPageAccess::freeMemory) + : m_pData (pData), m_nSize (nSize), m_destructor (destructor) + {} + + virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize); + +private: + /** Page (size aligned) access. + */ + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); + + /** Low level access. + */ + virtual storeError peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); + virtual storeError pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); + + virtual storeError getSize_Impl (sal_uInt32 & rnSize); + virtual storeError setSize_Impl (sal_uInt32 nSize); + +protected: + virtual ~MemoryPageAccess(); + +private: + /** Not implemented. + */ + MemoryPageAccess (MemoryPageAccess const &); + MemoryPageAccess & operator= (MemoryPageAccess const &); +}; + +storeError MemoryPageAccess::initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) +{ + (void) eAccessMode; // UNUSED + (void) nPageSize; // UNUSED + return store_E_Unknown; // NYI +} +MemoryPageAccess::~MemoryPageAccess() +{ + if (m_destructor != 0) + { + // release resource. + (*m_destructor)(m_pData, m_nSize); + } +} +storeError MemoryPageAccess::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) +{ + /* OSL_PRECOND(nOffset % size == 0, "Unaligned page read."); */ + PageHolder page (reinterpret_cast< PageData* >(m_pData + nOffset)); + swap<PageHolder>(page, rPage); + return store_E_None; +} +storeError MemoryPageAccess::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) +{ + PageData const * pagedata = rPage.get(); + if (!(pagedata != 0)) + return store_E_InvalidParameter; + +#if 0 /* NYI */ + sal_uInt16 const bytes = pagedata->size(); // Descr.m_nSize; + OSL_ASSERT(bytes >= PageData::thePageSize); + + offset = rPage.location(); // Descr.m_nAddr; + OSL_ASSERT(nOffset == offset); + + OSL_PRECOND(offset % bytes == 0, "Unaligned page write."); +#endif /* NYI */ + return pokeAt (nOffset, pagedata, pagedata->size()); +} +storeError MemoryPageAccess::peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + // [SECURITY:ValInput] + sal_uInt8 * dst_lo = static_cast<sal_uInt8*>(pBuffer); + if (!(dst_lo != 0)) + return store_E_InvalidParameter; + + sal_uInt8 * dst_hi = dst_lo + nBytes; + if (!(dst_lo <= dst_hi)) + return store_E_InvalidParameter; + + // ... + sal_uInt8 const * src_lo = m_pData + nOffset; + if (!(src_lo <= m_pData + m_nSize)) + return store_E_CantSeek; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if (!(src_hi <= m_pData + m_nSize)) + return store_E_CantRead; + + // copy. + memcpy (pBuffer, src_lo, (src_hi - src_lo)); + return store_E_None; +} +storeError MemoryPageAccess::pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) +{ + // [SECURITY:ValInput] + sal_uInt8 const * src_lo = static_cast<sal_uInt8 const*>(pBuffer); + if (!(src_lo != 0)) + return store_E_InvalidParameter; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if (!(src_lo <= src_hi)) + return store_E_InvalidParameter; + + sal_uInt64 const uSize = nOffset + nBytes; + if (uSize > SAL_MAX_UINT32) + return store_E_CantSeek; + + // ... + if (uSize > m_nSize) + { + // increase size. + storeError eErrCode = setSize (sal::static_int_cast<sal_uInt32>(uSize)); + if (eErrCode != store_E_None) + return eErrCode; + } + + sal_uInt8 * dst_lo = m_pData + nOffset; + if (!(dst_lo <= m_pData + m_nSize)) + return store_E_CantSeek; + + sal_uInt8 * dst_hi = dst_lo + nBytes; + if (!(dst_hi <= m_pData + m_nSize)) + return store_E_CantWrite; + + // copy. + memcpy (dst_lo, src_lo, (src_hi - src_lo)); + return store_E_None; +} +storeError MemoryPageAccess::getSize_Impl (sal_uInt32 & rnSize) +{ + rnSize = m_nSize; + return store_E_None; +} +storeError MemoryPageAccess::setSize_Impl (sal_uInt32 nSize) +{ + if (nSize != m_nSize) + { + sal_uInt8 * pData = static_cast<sal_uInt8*>(rtl_reallocateMemory (m_pData, nSize)); + if (pData != 0) + { + if (nSize > m_nSize) + memset (pData + m_nSize, 0, sal::static_int_cast< size_t >(nSize - m_nSize)); + } + else + { + if (nSize != 0) + return store_E_OutOfMemory; + } + m_pData = pData, m_nSize = nSize; + } + return store_E_None; +} +void MemoryPageAccess::freeMemory (sal_uInt8 * pData, sal_uInt32 /*nSize*/) +{ + rtl_freeMemory (pData); +} + +/*===*/ + +class MappedPageAccess : public MemoryPageAccess +{ + /** @see MemoryPageAccess::destructor_type callback function. + */ + static void unmapFile (sal_uInt8 * pData, sal_uInt32 nSize); + +public: + MappedPageAccess (sal_uInt8 * pData, sal_uInt32 nSize); + + virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize); + + virtual storeError writePageAt (PageHolder const & rPage, sal_uInt32 nOffset); + +private: + virtual storeError pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); + virtual storeError setSize_Impl (sal_uInt32 nSize); + +protected: + virtual ~MappedPageAccess() {} +}; + +MappedPageAccess::MappedPageAccess (sal_uInt8 * pData, sal_uInt32 nSize) + : MemoryPageAccess (pData, nSize, MappedPageAccess::unmapFile) +{ +} +storeError MappedPageAccess::initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) +{ + OSL_PRECOND(eAccessMode == store_AccessReadOnly, "store::MappedPageAccess: invalid AccessMode"); + return MemoryPageAccess::initialize (eAccessMode, nPageSize); +} +storeError MappedPageAccess::writePageAt (PageHolder const & /*rPage*/, sal_uInt32 /*nOffset*/) +{ + return store_E_AccessViolation; +} +storeError MappedPageAccess::pokeAt_Impl (sal_uInt32 /*nOffset*/, void const * /*pBuffer*/, sal_uInt32 /*nBytes*/) +{ + return store_E_AccessViolation; +} +storeError MappedPageAccess::setSize_Impl (sal_uInt32 /*nSize*/) +{ + return store_E_AccessViolation; +} +void MappedPageAccess::unmapFile (sal_uInt8 * pData, sal_uInt32 nSize) +{ + (void) osl_unmapFile (pData, nSize); +} + +#if 0 /* NYI */ +storeError MemoryPageAccess_createInstance ( + rtl::Reference< IPageAccess > & rxPageAccess, + storeAccessMode eAccessMode, + sal_uInt16 nPageSize +) +{ + rxPageAccess = new MemoryPageAccess(); + if (!rxPageAccess.is()) + return store_E_OutOfMemory; + + return rxPageAccess->initialize (eAccessMode, nPageSize); +} + +storeError FilePageAccess_createInstance ( + rtl::Reference< IPageAccess > & rxPageAccess, + rtl_uString * pFilename, + storeAccessMode eAccessMode, + sal_uInt16 nPageSize +) +{ + // Acquire file handle. + ResourceHolder<FileHandle> xFile; + result = xFile.get().initialize (pFilename, MODE_TO_NATIVE(eAccessMode)); + if (result != osl_File_E_None) + return ERROR_FROM_NATIVE(result); + + if (eAccessMode == store_AccessReadOnly) + { + ResourceHolder<FileMapping> xMapping; + result = xMapping.get().initialize (xFile.get()); + if (result == osl_File_E_None) + { + const sal_uInt32 nSize = sal::static_int_cast<sal_uInt32>(xMapping.get().m_uSize); + rxPageAccess = new MappedPageAccess (xMapping.get().m_pAddr, nSize); + if (!rxPageAccess.is()) + return store_E_OutOfMemory; + (void) xMapping.release(); + } + } + if (!rxPageAccess.is()) + { + rxPageAccess = new FilePageAccess (xFile.get()); + if (!rxPageAccess.is()) + return store_E_OutOfMemory; + (void) xFile.release(); + } + return rxPageAccess->initialize (eAccessMode, nPageSize); +} +#endif /* NYI */ + +/*======================================================================== + * + * test... + * + *======================================================================*/ +#if 0 /* NYI */ + +struct IDataBlock +{ + virtual sal_uInt16 singleCount() const = 0; + virtual sal_uInt32 singleLink (sal_uInt16 nIndex) const = 0; + virtual void singleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) = 0; + + virtual storeError get() = 0; + virtual storeError put() = 0; + virtual storeError truncate() = 0; +}; + +struct InodePageData : public PageData +{ + virtual INameBlock & getNameBlock() = 0; + virtual IDataBlock & getDataBlock() = 0; +}; + +template< class page_data_type > +page_data_type * query (PageData *, page_data_type *); + +template<> InodePageDataV2* +query (PageData & rData, InodePageDataV2 *) +{ + if (rData.isKindOf(InodePageDataV2::m_nTypeId)) + return static_cast<InodePageDataV2*>(&rData); + return 0; +} + +class InodePageObject : public PageObject +{ +public: + static InodePageObject createInstance (PageData & rData) + { + if (query(&rData, static_cast<InodePageDataV2*>(0))) + return InodePageObjectV2 (static_cast<InodePageDataV2&>(rData)); + else if (query(&rData, static_cast<InodePageDataV1*>(0))) + return InodePageObjectV1 (static_cast<InodePageDataV1&>(rData)); + } +}; + +#endif /* NYI */ + +/*======================================================================== + * + * main. + * + *======================================================================*/ + +#include <stdio.h> + +#if 0 /* EXP */ +class Interface +{ +public: + virtual void deallocate(void *) /* = 0 */; +}; + +class Implementation : public Interface +{ + SharedCount m_count; + +public: + Implementation() : Interface() { printf("Ctor(%p)\n", this); } + ~Implementation() { printf("Dtor(%p)\n", this); } + + Implementation (Implementation const & rhs) : Interface(), m_count (rhs.m_count) { printf("CopyCtor(%p)\n", this); } + + virtual void deallocate(void *) {} +}; + +Interface Interface_createInstance() +{ + Implementation aInst; + return aInst; +} +#endif /* EXP */ + +int SAL_CALL main (int argc, char ** argv) +{ + OSL_PRECOND(argc >= 1, "t_page: error: insufficient number of arguments."); + if (argc < 1) + return 0; + + { + void *a = (void*)1, *b = (void*)2; + swap<void*>(a, b); + } + { + PageObject a; + PageObject b (a); + PageObject c; + + c = b; + a = a; + + } + { + TestBIOS aBIOS; + TestClient aClient; + aClient.dwim (aBIOS); + } +#if 0 /* EXP */ + { + Interface aIfc1 (Interface_createInstance()); + Interface aIfc2 (aIfc1); + } +#endif /* EXP */ + + if (argc > 1) + { + rtl_uString * pFilename = 0; + rtl_uString_newFromAscii (&pFilename, argv[1]); + storeAccessMode eAccessMode = store_AccessReadOnly; + + // Acquire file handle. + ResourceHolder<FileHandle> h1; + oslFileError result = h1.get().initialize (pFilename, FilePageAccess::MODE_TO_NATIVE(eAccessMode)); + if (result == osl_File_E_None) + { + ResourceHolder<FileHandle> h2 (h1); + h1 = h2; + + if (eAccessMode == store_AccessReadOnly) + { + ResourceHolder<FileMapping> m1; + result = m1.get().initialize (h1.get()); + + const sal_uInt32 nSize = sal::static_int_cast<sal_uInt32>(m1.get().m_uSize); + (void) nSize; // UNUSED + + ResourceHolder<FileMapping> m2 (m1); + m1 = m2; + + result = osl_File_E_None; + } + } + } + + return 0; +} diff --git a/store/workben/t_store.cxx b/store/workben/t_store.cxx new file mode 100644 index 000000000000..cabd301cd5d2 --- /dev/null +++ b/store/workben/t_store.cxx @@ -0,0 +1,608 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: t_store.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#define _T_STORE_CXX "$Revision: 1.7.8.2 $" +#include <sal/types.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/time.h> +#include <rtl/ustring.hxx> +#include <store/store.hxx> + +#include <stdio.h> + +#if (defined(WNT) && defined(PROFILE)) +extern "C" +{ + void StartCAP (void); + void StopCAP (void); + void DumpCAP (void); +} +#endif /* PROFILE */ + +using rtl::OUString; + +/*======================================================================== + * + * Internals. + * + *======================================================================*/ +#define _DEMOSTOR_BUFSIZ 512 /* 4096, 1024, 512 */ +#define _DEMOSTOR_LOOPS 1000 /* 1000, 2000 */ + +#define _DEMOSTOR_REMOVE 0 +#define _DEMOSTOR_REBUILD 0 + +enum Options +{ + OPTION_HELP = 0x0001, + OPTION_FILE = 0x0002, + OPTION_PAUSE = 0x0004, + OPTION_REBUILD = 0x0008, + + OPTION_DUMP = 0x0010, + OPTION_ITER = 0x0020, + OPTION_LINK = 0x0040, + + OPTION_READ = 0x0100, + OPTION_WRITE = 0x0200, + OPTION_CREAT = 0x0400, + OPTION_TRUNC = 0x0800 +}; + +inline sal_Char ascii_toLowerCase (sal_Char ch) +{ + if ((ch >= 0x41) && (ch <= 0x5A)) + return (ch + 0x20); + else + return (ch); +} + +/*======================================================================== + * + * Timing. + * + *======================================================================*/ +struct OTime : public TimeValue +{ + OTime (void) + { + Seconds = 0; + Nanosec = 0; + } + + static OTime getSystemTime (void) + { + OTime tv; + osl_getSystemTime (&tv); + return tv; + } + + OTime& operator-= (const OTime& rPast) + { + Seconds -= rPast.Seconds; + if (Nanosec < rPast.Nanosec) + { + Seconds -= 1; + Nanosec += 1000000000; + } + Nanosec -= rPast.Nanosec; + return *this; + } + + friend OTime operator- (const OTime& rTimeA, const OTime& rTimeB) + { + OTime aTimeC (rTimeA); + aTimeC -= rTimeB; + return aTimeC; + } +}; + +/*======================================================================== + * + * DirectoryTraveller. + * + *======================================================================*/ +typedef store::OStoreDirectory Directory; + +class DirectoryTraveller : public Directory::traveller +{ + typedef store::OStoreFile file; + typedef Directory::iterator iter; + + store::OStoreFile m_aFile; + OUString m_aPath; + + sal_uInt32 m_nOptions; + unsigned int m_nLevel; + unsigned int m_nCount; + +public: + DirectoryTraveller ( + const file& rFile, + const OUString &rPath, + const OUString &rName, + sal_uInt32 nOptions, + unsigned int nLevel = 0); + + virtual ~DirectoryTraveller (void); + + virtual sal_Bool visit (const iter& it); +}; + +/* + * DirectoryTraveller. + */ +DirectoryTraveller::DirectoryTraveller ( + const file& rFile, + const OUString &rPath, + const OUString &rName, + sal_uInt32 nOptions, + unsigned int nLevel) + : m_aFile (rFile), + m_aPath (rPath), + m_nOptions (nOptions), + m_nLevel (nLevel), + m_nCount (0) +{ + m_aPath += rName; + m_aPath += OUString::createFromAscii("/"); +} + +/* + * ~DirectoryTraveller. + */ +DirectoryTraveller::~DirectoryTraveller (void) +{ +} + +/* + * visit. + */ +sal_Bool DirectoryTraveller::visit (const iter& it) +{ + m_nCount++; + if (m_nOptions & OPTION_DUMP) + { + rtl::OString aName (it.m_pszName, it.m_nLength, RTL_TEXTENCODING_UTF8); + printf ("Visit(%d,%d): %s [0x%08x] %d [Bytes]\n", + m_nLevel, m_nCount, + aName.pData->buffer, (unsigned int)(it.m_nAttrib), (unsigned int)(it.m_nSize)); + } + if (it.m_nAttrib & STORE_ATTRIB_ISDIR) + { + OUString aName (it.m_pszName, it.m_nLength); + if (aName.compareToAscii ("XTextViewCursorSupplier") == 0) + { + m_nCount += 1 - 1; + } + Directory aSubDir; + + storeError eErrCode = aSubDir.create ( + m_aFile, m_aPath, aName, store_AccessReadOnly); + if (eErrCode == store_E_None) + { + sal_uInt32 nRefCount = 0; + m_aFile.getRefererCount (nRefCount); + + DirectoryTraveller aSubTraveller ( + m_aFile, m_aPath, aName, m_nOptions, m_nLevel + 1); + aSubDir.travel (aSubTraveller); + } + } + return sal_True; +} + +/*======================================================================== + * + * main. + * + *======================================================================*/ +int SAL_CALL main (int argc, char **argv) +{ +#if (defined(WNT) && defined(PROFILE)) + StartCAP(); +#else + OTime aMainStartTime (OTime::getSystemTime()); +#endif /* PROFILE */ + + store::OStoreFile aFile; + storeError eErrCode = store_E_None; + + sal_uInt32 nOptions = 0; + for (int i = 1; i < argc; i++) + { + const char *opt = argv[i]; + if (opt[0] == '-') + { + switch (ascii_toLowerCase(sal_Char(opt[1]))) + { + case 'f': + nOptions |= OPTION_FILE; + break; + + case 'd': + nOptions |= OPTION_DUMP; + break; + case 'i': + nOptions |= OPTION_ITER; + break; + case 'l': + nOptions |= OPTION_LINK; + break; + + case 'r': + nOptions |= OPTION_READ; + break; + case 'w': + nOptions |= OPTION_WRITE; + break; + case 'c': + nOptions |= OPTION_CREAT; + break; + case 't': + nOptions |= OPTION_TRUNC; + break; + + case 'p': + nOptions |= OPTION_PAUSE; + break; + + case 'h': + default: + nOptions |= OPTION_HELP; + break; + } + } + else + { + if (nOptions & OPTION_FILE) + { + OUString aName ( + argv[i], rtl_str_getLength(argv[i]), + osl_getThreadTextEncoding()); + if ((nOptions & OPTION_CREAT) && (nOptions & OPTION_TRUNC)) + eErrCode = aFile.create (aName, store_AccessCreate); + else if (nOptions & OPTION_CREAT) + eErrCode = aFile.create (aName, store_AccessReadCreate); + else if (nOptions & OPTION_WRITE) + eErrCode = aFile.create (aName, store_AccessReadWrite); + else + eErrCode = aFile.create (aName, store_AccessReadOnly); + if (eErrCode != store_E_None) + { + printf ("Error: can't open file: %s\n", argv[i]); + exit (0); + } + } + } + } + + if ((nOptions == 0) || (nOptions & OPTION_HELP)) + { + printf ("Usage:\tt_store " + "[[-c] [-t] [-r] [-w]] [[-i] [-d] [-h]] " + "[-f filename]\n"); + + printf ("\nOptions:\n"); + printf ("-c\tcreate\n"); + printf ("-t\ttruncate\n"); + printf ("-r\tread\n"); + printf ("-w\twrite\n"); + printf ("-i\titerate\n"); + printf ("-d\tdump\n"); + printf ("-h\thelp\n"); + printf ("-f\tfilename\n"); + + printf ("\nExamples:"); + printf ("\nt_store -c -w -f t_store.rdb\n"); + printf ("\tCreate file 't_store.rdb',\n" + "\twrite fixed number (1000) of streams.\n"); + printf ("\nt_store -c -i -d -f t_store.rdb\n"); + printf ("\tOpen file 't_store.rdb', " + "create '/' directory,\n" + "\titerate directory tree, " + "dump directory info.\n"); + + exit (0); + } + + if (!aFile.isValid()) + { + eErrCode = aFile.createInMemory(); + if (eErrCode != store_E_None) + { + printf ("Error: can't create memory file\n"); + exit (0); + } + } + + // Stream Read/Write. + OUString aPath (RTL_CONSTASCII_USTRINGPARAM("/")); + if ((nOptions & OPTION_READ) || (nOptions & OPTION_WRITE)) + { + // Mode. + storeAccessMode eMode = store_AccessReadOnly; + if (nOptions & OPTION_WRITE) + eMode = store_AccessReadWrite; + if (nOptions & OPTION_CREAT) + eMode = store_AccessCreate; + + // Buffer. + char pBuffer[_DEMOSTOR_BUFSIZ] = "Hello World"; + pBuffer[_DEMOSTOR_BUFSIZ - 2] = 'B'; + pBuffer[_DEMOSTOR_BUFSIZ - 1] = '\0'; + + // Load/Save. +#ifndef PROFILE + OTime aStartTime (OTime::getSystemTime()); +#endif /* PROFILE */ + + for (int i = 0; i < _DEMOSTOR_LOOPS; i++) + { + OUString aName (RTL_CONSTASCII_USTRINGPARAM("demostor-")); + aName += OUString::valueOf ((sal_Int32)(i + 1), 10); + aName += OUString::createFromAscii (".dat"); + +#if (_DEMOSTOR_REMOVE == 1) + eErrCode = aFile.remove (aPath, aName); + if ((eErrCode != store_E_None ) && + (eErrCode != store_E_NotExists) ) + break; +#endif /* _REMOVE */ + + store::OStoreStream aStream; + eErrCode = aStream.create (aFile, aPath, aName, eMode); + if (eErrCode != store_E_None) + { + OSL_TRACE("OStoreStream(%d)::create(): error: %d", i, eErrCode); + break; + } + + if (nOptions & OPTION_TRUNC) + { + eErrCode = aStream.setSize(0); + if (eErrCode != store_E_None) + { + OSL_TRACE("OStoreStream(%d)::setSize(0): error: %d", i, eErrCode); + break; + } + } + + sal_uInt32 nDone = 0; + if (nOptions & OPTION_WRITE) + { + eErrCode = aStream.writeAt ( + 0, pBuffer, sizeof(pBuffer), nDone); + if (eErrCode != store_E_None) + { + OSL_TRACE("OStoreStream(%d)::writeAt(): error: %d", i, eErrCode); + break; + } + } + + if (nOptions & OPTION_READ) + { + sal_uInt32 nOffset = 0; + for (;;) + { + eErrCode = aStream.readAt ( + nOffset, pBuffer, sizeof(pBuffer), nDone); + if (eErrCode != store_E_None) + { + OSL_TRACE("OStoreStream(%d)::readAt(): error: %d", i, eErrCode); + break; + } + if (nDone == 0) + break; + nOffset += nDone; + } + } + + aStream.close(); + +#ifndef PROFILE + if (((i + 1) % (_DEMOSTOR_LOOPS/10)) == 0) + { + OTime aDelta (OTime::getSystemTime() - aStartTime); + + sal_uInt32 nDelta = aDelta.Seconds * 1000000; + nDelta += (aDelta.Nanosec / 1000); + + printf ("%d: %12.4g[usec]\n", (i+1), + (double)(nDelta)/(double)(i+1)); + } +#endif /* PROFILE */ + } + +#ifndef PROFILE + OTime aDelta (OTime::getSystemTime() - aStartTime); + + sal_uInt32 nDelta = aDelta.Seconds * 1000000; + nDelta += (aDelta.Nanosec / 1000); + + printf ("Total(rd,wr): %d[usec]\n", (unsigned int)(nDelta)); +#endif /* PROFILE */ + } + + // Link/Rename. + if (nOptions & OPTION_LINK) + { + // Create symlink to (root) directory. + eErrCode = aFile.symlink ( + aPath, OUString::createFromAscii("000000/"), + OUString(), aPath); + OSL_POSTCOND( + ((eErrCode == store_E_None ) || + (eErrCode == store_E_AlreadyExists) ), + "t_store::main(): store_symlink() failed"); + + // Create symlink to file. + OUString aLinkName (RTL_CONSTASCII_USTRINGPARAM("demostor-1.lnk")); + + eErrCode = aFile.symlink ( + aPath, aLinkName, + aPath, OUString::createFromAscii("demostor-1.dat")); + OSL_POSTCOND( + ((eErrCode == store_E_None ) || + (eErrCode == store_E_AlreadyExists) ), + "t_store::main(): store_symlink() failed"); + if ((eErrCode == store_E_None ) || + (eErrCode == store_E_AlreadyExists) ) + { + OUString aShortcut ( + RTL_CONSTASCII_USTRINGPARAM("Shortcut to demostor-1.dat")); + eErrCode = aFile.rename ( + aPath, aLinkName, + aPath, aShortcut); + OSL_POSTCOND( + ((eErrCode == store_E_None ) || + (eErrCode == store_E_AlreadyExists) ), + "t_store::main(): store_rename() failed"); + } + + // Create directory. + OUString aDirName (RTL_CONSTASCII_USTRINGPARAM("demostor-1.dir")); + store::OStoreDirectory aDir; + + eErrCode = aDir.create ( + aFile, aPath, aDirName, store_AccessReadCreate); + OSL_POSTCOND( + (eErrCode == store_E_None), + "t_store::main(): store_createDirectory() failed"); + if (eErrCode == store_E_None) + { +#if 0 /* NYI */ + // Rename directory. + eErrCode = aFile.rename ( + aPath, "demostor-1.dir/", + aPath, "Renamed demostor-1.dir"); + OSL_POSTCOND( + ((eErrCode == store_E_None ) || + (eErrCode == store_E_AlreadyExists) ), + "t_store::main(): store_rename() failed"); + + eErrCode = aFile.rename ( + aPath, "Renamed demostor-1.dir/", + aPath, "demostor-1.dir"); + OSL_POSTCOND( + (eErrCode == store_E_None), + "t_store::main(): store_rename() failed"); +#endif /* NYI */ + } + } + + // Directory iteration. + if (nOptions & OPTION_ITER) + { +#ifndef PROFILE + OTime aStartTime (OTime::getSystemTime()); +#endif /* PROFILE */ + OUString aEmpty; + + // Root directory. + store::OStoreDirectory aRootDir; + if (nOptions & OPTION_LINK) + { + // Open symlink entry. + eErrCode = aRootDir.create ( + aFile, aPath, OUString::createFromAscii("000000"), + store_AccessReadOnly); + } + else + { + // Open direct entry. + if (nOptions & OPTION_CREAT) + eErrCode = aRootDir.create ( + aFile, aEmpty, aEmpty, store_AccessReadCreate); + else if (nOptions & OPTION_WRITE) + eErrCode = aRootDir.create ( + aFile, aEmpty, aEmpty, store_AccessReadWrite); + else + eErrCode = aRootDir.create ( + aFile, aEmpty, aEmpty, store_AccessReadOnly); + } + + if (eErrCode == store_E_None) + { + // Traverse directory tree. + DirectoryTraveller aTraveller ( + aFile, aEmpty, aEmpty, nOptions, 0); + aRootDir.travel (aTraveller); + } + else + { + // Failure. + printf ("Error: can't open directory: \"/\"\n"); + } + +#ifndef PROFILE + OTime aDelta (OTime::getSystemTime() - aStartTime); + + sal_uInt32 nDelta = aDelta.Seconds * 1000000; + nDelta += (aDelta.Nanosec / 1000); + + printf ("Total(iter): %d[usec]\n", (unsigned int)(nDelta)); +#endif /* PROFILE */ + } + + if (nOptions & OPTION_PAUSE) + { + TimeValue tv; + tv.Seconds = 300; + tv.Nanosec = 0; + osl_waitThread (&tv); + } + + // Size. + sal_uInt32 nSize = 0; + aFile.getSize (nSize); + + // Done. + aFile.close(); + +#if (defined(WNT) && defined(PROFILE)) + StopCAP(); + DumpCAP(); +#endif /* PROFILE */ +#ifndef PROFILE + OTime aDelta (OTime::getSystemTime() - aMainStartTime); + + sal_uInt32 nDelta = aDelta.Seconds * 1000000; + nDelta += (aDelta.Nanosec / 1000); + + printf ("Total: %d[usec]\n", (unsigned int)(nDelta)); +#endif /* PROFILE */ + + return 0; +} |