// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// f32\sfile\sf_disk.cpp
//
//
#include "sf_std.h"
#if defined(_LOCKABLE_MEDIA)
LOCAL_C TInt DelayedWriter(TAny *aPtr);
LOCAL_C void DelayedWriterL(const TDelayedWriter *aDW);
EXPORT_C void WriteToDisk(const TDesC& aFileName, const TDesC8& aBuf)
//
// Launches as separate thread that writes the contents of the pbus pswd
// store to disk. It is possible that this function will be called again
// before the thread has finished writing. In that case, a new thread
// will be created and it will wait on the global DelayedWriteSem semaphore.
//
{
static TInt32 ctr = 0x00000000; // ctr to create unique thd names
__PRINT(_L("WriteToDisk"));
__PRINT1(_L("wtd:afn%S"), &aFileName);
TDelayedWriterInit dwi;
dwi.iFileName = &aFileName;
dwi.iData = &aBuf;
// Create local semaphore this thread can wait on until the child thread has
// made copies of the file name and the store data.
__PRINT(_L("wtd:cr sem"));
TBuf<3 + 8> semName;
semName.Format(_L("dws%08x"), ctr++);
dwi.iSemName = &semName;
RSemaphore svrSem;
if (svrSem.CreateGlobal(semName, 0) != KErrNone)
return;
// Spin off a thread with a unique name.
__PRINT(_L("wtd:cr thd"));
TName nm;
nm.Format(_L("dw%08x"), ctr);
RThread t;
TInt hminsz = Max(KHeapMinSize, aFileName.Length() + aBuf.Length() + 1024);
if (t.Create(
nm, DelayedWriter, KDefaultStackSize,
hminsz /* aHeapMinSize */, hminsz /* aHeapMaxSize */, &dwi) == KErrNone)
{
__PRINT(_L("wtd:set pri"));
t.SetPriority(EPriorityMuchLess); // run as low priority task
__PRINT(_L("wtd:res"));
t.Resume();
__PRINT(_L("wtd:wait"));
svrSem.Wait();
__PRINT(_L("wtd:cls thd"));
t.Close(); // get rid of our handle
}
__PRINT(_L("wtd:cls sem"));
svrSem.Close();
}
LOCAL_D TInt DelayedWriter(TAny *aPtr)
//
// Main thread function for thread that is spun off from WriteToDisk().
// After local copies of the data have been allocated (or failed), tell
// the server to continue.
//
{
__PRINT(_L("DelayedWriter"));
User::SetCritical(User::ESystemCritical);
TInt r;
TDelayedWriterInit *dwi = (TDelayedWriterInit *) aPtr;
RSemaphore svrSem; // signal svr when data copied
CTrapCleanup *th = NULL; // thread trap handler
TDelayedWriter *dw = NULL; // thread copy of data
RSemaphore queueSem; // queued delayed write threads
// Allocate a trap handler.
__PRINT(_L("dlw:alc tp"));
if ((th = CTrapCleanup::New()) == NULL)
{
r = KErrNoMemory;
goto cleanup;
}
// Make copies of the filename and store data.
__PRINT(_L("dlw:cp dat"));
TRAP(r, dw = TDelayedWriter::NewL(dwi));
if (r != KErrNone)
goto cleanup;
// Tell file server made local copies of data and so can continue.
__PRINT(_L("dlw:sg cp dat"));
if ((r = svrSem.OpenGlobal(*dwi->iSemName)) != KErrNone)
goto cleanup;
svrSem.Signal();
// Wait for the other store threads to finish.
__PRINT(_L("dlw:wait"));
if ((r = queueSem.OpenGlobal(_L("dwsem"))) != KErrNone)
goto cleanup;
queueSem.Wait();
// Write the data and signal the global semaphore so follow up threads can run.
__PRINT(_L("dlw:wrt"));
TRAP(r, DelayedWriterL(dw));
__PRINT1(_L("dlw:wrt r = %d"), r);
queueSem.Signal();
cleanup: // free any opened resources
__PRINT(_L("dlw:cln"));
svrSem.Close();
delete th;
delete dw;
queueSem.Close();
return KErrNone;
}
LOCAL_D void DelayedWriterL(const TDelayedWriter *aDW)
//
// Replace any existing store file; write data and set file as hidden and system.
//
{
__PRINT(_L("DelayedWriterL"));
RFs fs; // connect to the file server
CleanupClosePushL(fs);
User::LeaveIfError(fs.Connect());
RFile f; // replace any existing file
CleanupClosePushL(f);
__PRINT(_L("dlw: opn"));
// Create the directory if it doesn't already exist
TInt r;
r = fs.MkDirAll(*aDW->iFileName);
if (r != KErrNone && r != KErrAlreadyExists)
{
__PRINT(_L("dlw: MkDirAll err"));
User::Leave(r);
}
User::LeaveIfError(f.Replace(fs, *aDW->iFileName, EFileShareExclusive | EFileStream | EFileWrite));
__PRINT(_L("dlw: wrt"));
User::LeaveIfError(f.Write(*aDW->iData));
__PRINT(_L("dlw: sat"));
#ifndef __WINS__ // cannot replace hidden | system file in WINS.
User::LeaveIfError(f.SetAtt(KEntryAttHidden | KEntryAttSystem, 0x00000000));
#endif
__PRINT(_L("dlw: dst"));
CleanupStack::PopAndDestroy(2); // f, fs
}
//
// TDelayedWriter
//
TDelayedWriter *TDelayedWriter::NewL(const TDelayedWriterInit *dwi)
//
// static
// Allocates a TDelayedWriter structure on the thread's heap that is used to
// persist the data that the writer thread will need during its lifetime.
//
{
__PRINT(_L("TDelayedWriter::NewL"));
TDelayedWriter *self = new(ELeave) TDelayedWriter();
CleanupStack::PushL(self);
self->ConstructL(dwi);
CleanupStack::Pop(); // self
return self;
}
TDelayedWriter::TDelayedWriter()
{
__PRINT(_L("TDelayedWriter::TDelayedWriter"));
// empty.
}
void TDelayedWriter::ConstructL(const TDelayedWriterInit *dwi)
//
// 2y initialisation. Makes own copy of filename and data.
// Fields are not popped onto CleanupStack because will be deleted in dtor
//
{
__PRINT(_L("TDelayedWriter::ConstructL"));
iFileName = dwi->iFileName->AllocL();
iData = dwi->iData->AllocL();
}
TDelayedWriter::~TDelayedWriter()
//
// dtor - frees filename and store data that was allocated in ConstructL().
//
{
__PRINT(_L("TDelayedWriter::~TDelayedWriter"));
delete iFileName; // alloc in ConstructL()
delete iData; // alloc in server
}
#else
EXPORT_C void WriteToDisk(const TDesC& /*aFileName*/, const TDesC8& /*aBuf*/)
//
//
//
{}
#endif