diff -r 88ee4cf65e19 -r 1aa8c82cb4cb remotestoragefw/remotefilesystemplugin/src/rsfwfsfilecb.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remotestoragefw/remotefilesystemplugin/src/rsfwfsfilecb.cpp Wed Sep 01 12:15:08 2010 +0100 @@ -0,0 +1,473 @@ +/* +* Copyright (c) 2003-2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: File server interface class representing an open file. +* Allows to access a specific remote file. +* +*/ + + +// INCLUDE FILES +#include "rsfwfsfilecb.h" +#include "rsfwfsmountcb.h" + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::CRsfwFsFileCB +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CRsfwFsFileCB::CRsfwFsFileCB() + { + iLastFlushFailed = ETrue; + iPartialWriteSupported = ETrue; + } + +// Destructor +CRsfwFsFileCB::~CRsfwFsFileCB() + { + // close the cache file first so that RFE can move/delete it if upload fails + iContFile.Close(); + TUint flags = 0; + if (iFileName) + { + if (!iLastFlushFailed) + { + // Now the container file has been changed, + // tell Remote File Engine to update it on the servers + // RSessionL() should not leave here as the remote session surely is created by now... + if (iAtt & KEntryAttModified) + { + flags |= ECloseModified; + + // File was modified use, flush to write data to the server + // We write the whole file always, if flush was never called we cannot + // know whether partial write is supported. + TRAP_IGNORE(static_cast + (Mount()).RSessionL()->Flush(iThisFid, 0, iCachedSize, iCachedSize)); + } + else + { + flags |= ECloseNotModified; + } + + } + else + { + // flush was called and failed + // do not try to flush again if the application closes the file + // instead indicate this to the close state machine + flags |= ECloseLastFlushFailed; + } + } + + // close will release the write lock if possible + // and also allows user to save the file locally if flush failed + TRAP_IGNORE(static_cast + (Mount()).RSessionL()->CloseFile(iThisFid, flags)); + + } + + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::RenameL +// Renames the file with the full file name provided. Because the full name of +// the file includes the path, the function can also be used to move the file. +// +// It can be assumed that no other sub-session has access to the file: +// i.e. the file has not been opened in EFileShareAny share mode. +// It can also be assumed that the file has been opened for writing. +// ----------------------------------------------------------------------------- +// +void CRsfwFsFileCB::RenameL( + const TDesC& aNewName) + { + static_cast(Mount()).RenameFidL(iParentFid, *iFileName, aNewName); + delete iFileName; + iFileName = NULL; + iFileName = aNewName.AllocL(); + } + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::ReadL +// Reads a specified number of bytes from the open file starting at +// the specified position, and writes the result into a descriptor. +// +// It can be assumed that aPos is inside the file and aLength > 0. +// The file should only be read up to its end regardless of +// the value of aPos + aLength. The number of bytes read should be stored +// in aLength on return. +// +// Implemented by sending FETCH request to Remote File Engine for the +// specified data and subsequently reading the data from the local cache file. +// Reading the local cache file sets aLength. +// Note that we want to keept the cache file continuos. If the requested data +// starts behind the end of the current cache file, the function sends FETCHDATA +// and Remote File Engine puts this data into a temp cache file valid only +// for the duration of this operation if the caching mode is something else than +// Whole File Caching +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CRsfwFsFileCB::ReadL( + TInt aPos, + TInt& aLength, + const TAny* /*aDes*/, + const RMessagePtr2& aMessage) + + { + + if (iCachedSize == 0) + { + // iCachedSize possibly not up-to-date... + iContFile.Size(iCachedSize); + } + + HBufC8* data = HBufC8::NewMaxLC(aLength); + TPtr8 buf(data->Des()); + + if (aPos > iCachedSize) + { + // Depending on the caching mode this type of request may bypass the + // normal cache file. + TBool useTempCache = EFalse; + HBufC* tmpCacheFile = HBufC::NewLC(KMaxPath); + TPtr tmpCache(tmpCacheFile->Des()); + User::LeaveIfError(static_cast + (Mount()).RSessionL()->FetchData(iThisFid, + aPos, + aPos + aLength - 1, + tmpCache, + useTempCache)); + if (useTempCache) + { + // use "temp" in the same directory instead of the cache file + RFile tempFile; + TParse parser; + parser.Set(tmpCache, NULL, NULL); + HBufC* tempPath = HBufC::NewLC(KMaxPath); + TPtr tempptr = tempPath->Des(); + tempptr.Append(parser.DriveAndPath()); + tempptr.Append(KTempFileName); + User::LeaveIfError(tempFile.Open(*(RFs* )Dll::Tls(), + tempptr, EFileRead)); + CleanupStack::PopAndDestroy(tempPath); + CleanupClosePushL(tempFile); + User::LeaveIfError(tempFile.Read(buf, aLength)); + CleanupStack::PopAndDestroy(&tempFile); + } + else + { + // read from the normal container file (Whole File Caching mode). + iContFile.Size(iCachedSize); + User::LeaveIfError(iContFile.Read(aPos, buf, aLength)); + } + CleanupStack::PopAndDestroy(tmpCacheFile); // tempcacheFile + } + else if ((aPos + aLength) > iCachedSize) + { + User::LeaveIfError(static_cast + (Mount()).RSessionL()->Fetch(iThisFid, + aPos, + aPos + aLength - 1, + iCachedSize)); + + User::LeaveIfError(iContFile.Read(aPos, buf, aLength)); + } + else + { + User::LeaveIfError(iContFile.Read(aPos, buf, aLength)); + } + + aMessage.WriteL(0, buf, 0); + CleanupStack::PopAndDestroy(data); + if (iCachedSize == iSize) + { + // clear the remote attribute if the whole file has now been fetched + iAtt &= ~KEntryAttRemote; + } + } + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::WriteL +// Writes data to the open file. iModified and iSize are set by the file server +// after this function has completed successfully. +// +// It can be assumed that aPos is within the file range and aLength > 0. +// When aPos + aLength is greater than the file size then the file should +// be enlarged using SetSizeL(). The number of bytes written should be +// returned through the argument aLength. +// +// Implemented by writing to the local cache file. First requests Remote File +// Engine whether there is enough space in the cache to write the file (this +// also calls SysUtil::DiskSpaceBelowCritical()). FE attempts to free space +// from the cache if necessary Implementation notice: writes a large file in +// chunks of 64K. +// +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CRsfwFsFileCB::WriteL( + TInt aPos, + TInt& aLength, + const TAny* /*aDes*/, + const RMessagePtr2& aMessage) + { + + if (iCachedSize == 0) + { + // iCachedSize possibly not up-to-date... + iContFile.Size(iCachedSize); + } + + // if flush was cancelled, but we come again to write, again set iLastFlushFailed to EFalse + iLastFlushFailed = EFalse; + + // We must first fetch the file to the local cache + // unless aPos = 0 and aLength => iSize + // Note that if files are written to they cannot be partially cached + // as the whole file will be sent to the server and overwrites the old file. + // That is why we must ensure that the whole file is cached as soon as we + // get the first write. + // in subsequent writes iCachedSize will equal iSize + // This may eventually change if we start to use some kind of "delta-PUT". + if (!((aPos == 0) && (aLength >= iSize)) && iCachedSize < iSize && !iFetchedBeforeWriting) + { + User::LeaveIfError(static_cast + (Mount()).RSessionL()->Fetch(iThisFid, iCachedSize, iSize-1, iCachedSize)); + iFetchedBeforeWriting = ETrue; + } + + // make sure that a potential cache addition still fits into the cache + TInt sizeToBeWritten = 0; + + if (iSize > iCachedSize) + { + // when current Write is executed as a part of Copy operation + // then iSize has been set to final size, even before any writing started + sizeToBeWritten = iSize - iCachedSize; + } + else if (aPos + aLength > iCachedSize) + { + sizeToBeWritten = aPos + aLength - iCachedSize + iWrittenSize; + } + + TBool okToWrite; + User::LeaveIfError(static_cast + (Mount()).RSessionL()->OkToWrite(iThisFid, + sizeToBeWritten, + okToWrite)); + + if (!okToWrite) + { + User::Leave(KErrDiskFull); + } + + TInt anOffset = 0; + HBufC8* data = HBufC8::NewMaxLC(aLength); + TPtr8 buf(data->Des()); + + aMessage.ReadL(0, buf, anOffset); + + User::LeaveIfError(iContFile.Write(aPos, *data, aLength)); + User::LeaveIfError(iContFile.Flush()); + CleanupStack::PopAndDestroy(data); + + // update iCachedSize and iWrittenSize if the container file size has grown + if (aPos + aLength > iCachedSize) + { + iCachedSize = aPos + aLength; + iWrittenSize = sizeToBeWritten; + } + + // for flush() calls after this call: + // set iFlushedSize to aPos, so that changes will be flushed + if (iFlushedSize > aPos) + { + iFlushedSize = aPos; + } + + } + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::SetSizeL +// Emply implementation, upper class already set iSize +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CRsfwFsFileCB::SetSizeL( + TInt aSize) + { + iReportedSize = aSize; + // we cannot set the actual size of the remote file, but also we do not + // return KErrNotSupported as that would cause problems with CFileMan + // and File Manager, which use SetSize() as an optimization to set the + // target file size in copy. + // Propably calling setsize() on remote files when for example just writing + // to an existing file would cause weird results. + } + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::SetEntryL +// Sets the attribute mask, iAtt, and the modified time of the file, iModified. +// If aMask|aVal does not equal zero, then aMask should be OR'ed with iAtt, +// whilst the inverse of aVal should be AND'ed with iAtt. +// If the modified flag is set in aMask then iModified should be set to aTime. +// +// Implemented by calling CRsfwFsMountCB::SetEntryL(). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CRsfwFsFileCB::SetEntryL( + const TTime& aTime, + TUint aMask, + TUint aVal) + { + static_cast(Mount()).SetEntryL(*iFileName, + aTime, + aMask, + aVal); + } + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::FlushAllL +// Flushes, to disk, all cached file data (e.g. attributes, modification time, +// file size). The modified bit in the file attributes mask should be cleared if +// the flush was successful. +// +// File Server calls this before reading directory entries, getting an entry +// details for a directory entry etc. The idea is to make sure that all the +// information to be retrieved is up to date. We don't need to implement this, +// as our framework does not have buffers that could cause this problem. +// +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CRsfwFsFileCB::FlushAllL() + { + } + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::FlushDataL +// Flushes, to disk, the cached information necessary for the integrity +// of recently written data, such as the file size. +// +// Called by File Server as a result of RFile::Flush() (if the file has been +// modified). In our framework the file should be written to the server. +// We should also clear KEntryAttModified here. +// +// (other items were commented in a header). +// +// ----------------------------------------------------------------------------- +// +void CRsfwFsFileCB::FlushDataL() + { + TInt err = KErrNone; + + // close the container file to make sure all the local changes are cached + iContFile.Close(); + + // if flush was cancelled, but we come again to write, + // again set lastflushfailed to EFale + iLastFlushFailed = EFalse; + + // may attempt to write part of the file or whole file + // also we may or may not know for sure whether the + // server supports partial write +starttoflush: + if (!iPartialWriteSupported) + { + // If we know that partial write is not supported + // AND the client has reported the full size of + // the file, do not really flush until all the data + // has been written to the cache file. + // * + // If we do not know the total size flush whatever is cached + if ((iCachedSize == iReportedSize) || iReportedSize == 0) + { + err = static_cast + (Mount()).RSessionL()->Flush(iThisFid, + 0, + iCachedSize, + iCachedSize); + } + // else do not do anything yet, only when the whole file is in cache + } + else + { + // we "still" assume that partial write is supported + err = static_cast + (Mount()).RSessionL()->Flush(iThisFid, + iFlushedSize, + iCachedSize, + iReportedSize); + if (err == KErrNotSupported) + { + err = KErrNone; // reset the error + // flushing the file not supported + // probably because the access protol plugin does not support partial write + iPartialWriteSupported = EFalse; + // apply the flush logic again + // this time with the knowledge that the server does not support partial + // write + goto starttoflush; + } + else + { + iAtt &= ~KEntryAttModified; // clear KEntryAttModified if flush worked + } + + } + + // re-open the container file + User::LeaveIfError(iContFile.Open(*(RFs* )Dll::Tls(), + iCachePath, + EFileWrite | EFileShareAny)); + + + // handling the results + if (err == KErrNone) + { + // the operation was successful + iFlushedSize = iCachedSize; + } + else if (err != KErrNone) + { + iLastFlushFailed = ETrue; + User::Leave(err); + } + + } + +// ----------------------------------------------------------------------------- +// CRsfwFsFileCB::SetContainerFileL +// Opens the container file. +// Called in CRsfwFsMountCB when the file is opened. +// Implementation notice: If this file is only opened for reading, it would +// seem sensible to open EFileRead|EFileShareAny here, but when Remote +// File Engine then tries to open EFileWrite|EFileShareAny it fails unless +// EFileWrite is specified here also... +// +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CRsfwFsFileCB::SetContainerFileL( + const TDesC& aPath) + { + iCachePath = aPath; + User::LeaveIfError(iContFile.Open(*(RFs* )Dll::Tls(), + aPath, + EFileWrite | EFileShareAny)); + } + +// End of File