How to backup a sis file while it is being installed
S60 5th Edition
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.
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".
TInt err = fs.Connect();
TBool done = EFalse;
CFileList* fl = NULL;
if (fl==NULL) /** the NextL should be called repeatly untill it returns NULL*/
done = ETrue;
TInt count = fl->Count();
for (TInt i= 0; (i<count)&&(!done); i++) /** for all the open files */
TEntry entry = (*fl)[i];
if((parse.Ext()==KExtSis)||(parse.Ext()==KExtSisx)) /** first the first sis file */
filename = entry.iName;
done = ETrue;
/** we found the sis file! NOTE: the file name has no drive letter */
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,
|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)
/** 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 */
/** Messaging application's private folder, try to retrieve the file by Messaging APIs */
/** Other private folders, no idea how to read the sis file */
/** Sys folders, no idea how to read the sis file */
/** other folders (including the resource folder) */
filename.Insert(0, KDriveC); /** the file name has no drive letter, so we insert a placeholder */
TBool found = EFalse;
err = fs.DriveList(driveList);
for(TInt driveNumber=EDriveA; (driveNumber<EDriveZ)&&(!found); driveNumber++)
if (driveList[driveNumber]) /** now we iterate through all the available drives */
err = fs.DriveToChar(driveNumber,driveLetter);
filename = driveLetter;
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;
/** we found the file! make a copy to the designated location */
err = BaflUtils::CopyFile(fs, filename, KSisBackup);
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.
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.