×
Namespaces

Variants
Actions

How to backup a sis file while it is being installed

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata
Tested with
Devices(s): S60
Compatibility
Platform(s): Symbian
S60 5th Edition
Article
Keywords: TOpenFileScan
Created: chenziteng (19 Jan 2010)
Last edited: hamishwillee (24 Jun 2011)

Contents

Overview

There are several S60 applications, free or commercial, support the "Bluetooth share" feature, for example the popular freeware Paint Pad has a "Share application" menu item, when selected it will send a copy of its installation package to a peer device via Bluetooth. From what observed, during installation the application can backup its sis file to the system drive (C: drive) for later use. This article, together with a full example, demonstrates how the feature can be done.

Solutions

The overall solution can be summarized in a simple sentence: we need to develop an executable that runs during installation; it should find the containing sis file and then copy it to a designated location. The first part of the sentence is very straightforward to implement by the Advanced Package File Options FR, RI, and RW etc (NOTE: the options don't take effect when the sis file is self-signed), so we then focus on the second part.

Well before discussing how to find the sis file being installed; let's make two assumptions to simply our investigation.

Assumption 1: A sis file is open while it is being installed

The assumption can easily be verified by the following test case,

Step 1: Use the S60 File manager to open a sis file

Step 2: Use another file manager to delete the sis file, an "Already in use!" prompt will be shown, means the sis file is open (being used by the installer)

Assumption 2: Only one sis file can be installed at a time

It can be verified by a similar test case,

Step 1: Use the S60 File manager to open a sis file, and proceed till you see the memory selection dialog.

Step 2: Use another file manager to open the sis file, an "Installer already in use could not start!" prompt will be shown, means the installer is singleton.

Under the assumptions the question can be more specific: how to find an open sis file? (Of course further identifications can be made, for example checking the UID of the file). A very obvious answer is to recursively iterate through the file system and find the file, so let's list it as the candidate solution 1,

Candidate solution 1: Recursively iterate through the file system and find an open sis file

It is absolutely possible to implement the solution by manipulating File Server client APIs, for example TFindFile or CDirScan, but there might be hundreds of files in tens of folders in both system drive and mass storage, so it would be better if we can reduce the file scan scope to avoid long wait during installation. Hopefully, there is a system API called TOpenFileScan which can get a list of open files - exactly what we want!

Candidate solution 2: Use TOpenFileScan to iterate through the open files and find the one

Be careful there are two pitfalls along the way, first every TOpenFileScan::NextL() call creates a list of the files opened by a particular file server session, so it must be called within a loop until it returns NULL or the file is found. And second the file names retrieved have no drive letter, for example "\\data\\HelloWorld.sis" instead of "C:\\data\\HelloWorld.sis".

...
_LIT(KExtSis, ".sis");
_LIT(KExtSisx, ".sisx");
RFs fs;
TInt err = fs.Connect();
User::LeaveIfError(err);
CleanupClosePushL(fs);
TFileName filename;
TOpenFileScan ofs(fs);
TBool done = EFalse;
while(!done)
{
CFileList* fl = NULL;
ofs.NextL(fl);s
if (fl==NULL) /** the NextL should be called repeatly untill it returns NULL*/
{
done = ETrue;
}
else
{
CleanupStack::PushL(fl);
TInt count = fl->Count();
for (TInt i= 0; (i<count)&&(!done); i++) /** for all the open files */
{
TEntry entry = (*fl)[i];
TParsePtrC parse(entry.iName);
if((parse.Ext()==KExtSis)||(parse.Ext()==KExtSisx)) /** first the first sis file */
{
filename = entry.iName;
done = ETrue;
}
}
CleanupStack::PopAndDestroy(fl);
}
}
if(filename!=KNullDesC)
{
/** we found the sis file! NOTE: the file name has no drive letter */
}
CleanupStack::PopAndDestroy(&fs);
...

Now the file name is here, but in a file system that supports Data caging a program may not always be able to copy a file from one place to another, so before taking further action on the file let's check where it is stored,

Folder Comments
Messaging application's \private folder This means the file was sent via Bluetooth, or via IrDA, or via other messaging protocols like MMS and email. In this case the file can only be retrieved by Messaging APIs.
Other \private folders Less possible, so ignore this case.
\resource folder Less possible, and applications can read the resource folder without any problem.
\sys folder Less possible, so ignore this case.


and then we can continue coding. If the sis file is in the private folder of the Messaging application, then we have to use the Messaging APIs to retrieve it. The usage of Messaging API is not the emphasis of the article so I will not explain more here, however the full example attached can handle Bluetooth attachment so please review the implementation of CSmsHandler::ExportInboxToFileL() if you have interest.

As mentioned earlier, the retrieved file name has no driver letter, so we have to list all the available drives by RFs::DriveList() and then check one by one if the file is in the drives, and when we find one we need to further check if it is open (can not be modified). If everything goes well then finally we will complete the file name with a drive letter, and then we can copy it to the designated location (in this example the c:\sisback folder)

...
_LIT(KSisBackup, "c:\\sisbackup\\backup.sis");
_LIT(KMessagingPrivateFolder, "\\private\\1000484b\\");
_LIT(KPrivateFolder, "\\private\\");
_LIT(KSysFolder, "\\sys\\");
...
if(filename!=KNullDesC)
{
/** we found the sis file! */
 
BaflUtils::EnsurePathExistsL(fs, KSisBackup); /** create the folder structure if doesn't already exist */
 
filename.LowerCase(); /** all chars in lower case so that we can get correct compare result */
 
if(filename.Find(KMessagingPrivateFolder)==0)
{
/** Messaging application's private folder, try to retrieve the file by Messaging APIs */
}
else if(filename.Find(KPrivateFolder)==0)
{
/** Other private folders, no idea how to read the sis file */
}
else if(filename.Find(KSysFolder)==0)
{
/** Sys folders, no idea how to read the sis file */
}
else
{
/** other folders (including the resource folder) */
 
_LIT(KDriveC, "c:");
filename.Insert(0, KDriveC); /** the file name has no drive letter, so we insert a placeholder */
TBool found = EFalse;
TDriveList driveList;
err = fs.DriveList(driveList);
User::LeaveIfError(err);
for(TInt driveNumber=EDriveA; (driveNumber<EDriveZ)&&(!found); driveNumber++)
{
if (driveList[driveNumber]) /** now we iterate through all the available drives */
{
TChar driveLetter;
err = fs.DriveToChar(driveNumber,driveLetter);
User::LeaveIfError(err);
filename[0] = driveLetter;
TEntry entry;
err = fs.Entry(filename, entry);
if(err==KErrNone) /** and check if the file is in the drive */
{
err = fs.SetModified(filename, entry.iModified); /** if it exists and can not be modified then it is the one */
if(err!=KErrNone) /** KErrInUse, or KErrPermissionDenied if the file is in the resource folder */
{
found = ETrue;
}
}
}
}
if(found)
{
/** we found the file! make a copy to the designated location */
err = BaflUtils::CopyFile(fs, filename, KSisBackup);
User::LeaveIfError(err);
}
}
}
...

The 'mission' seems complete, but before we end the discussion there are two more problems to be considered

(1) Remember to remove the backup file during un-installation. This can easily be resolved by adding a "FN" line in the .pkg file

...
"" - "c:\sisbackup\backup.sis", FN
...

(2) If the installation is cancelled then there should be no backup file. The example doesn't handle the problem properly and I hope someone can fix it and update the article.

Example

Full example: HelloWorld(SisBackup).zip

The example can be built on S60 5th Edition SDK and has been tested on a S60 5th Edition phone.

How to use:

1. Build the \SisBackup program for target

2. Build the \HelloWorld application for target and then make a sis file

3. Sign the HelloWorld.sis with a Symbian Signed certificate

4. Copy the signed sis to the phone memory/mass storage, or sending it to the phone via Bluetooth

5. Install the signed sis and then start the HelloWorld application, and then select "Options"->"Share" if you see a message "c:\sisbackup\backup.sis" it means the sis file has been successfully copied to the system drive.

References

Advanced Package File Options

TSS000718 - Using RUNREMOVE and RUNINSTALL options in SIS packages

Scanning folders & subfolders in Symbian devices

Find Files

How to get a sis file name while this sis file is installing?

How to get Drive Information

How to get the attachments from an EMail

This page was last modified on 24 June 2011, at 12:17.
80 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×