--- /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<CRsfwFsMountCB&>
+ (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<CRsfwFsMountCB&>
+ (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<CRsfwFsMountCB&>(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<CRsfwFsMountCB&>
+ (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<CRsfwFsMountCB&>
+ (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<CRsfwFsMountCB&>
+ (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<CRsfwFsMountCB&>
+ (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<CRsfwFsMountCB&>(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<CRsfwFsMountCB&>
+ (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<CRsfwFsMountCB&>
+ (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