Fixed threadpool hang and added lots of smoketests.
* Fixed bug in threadpool logic when calling CleanupAnyWorkersSharingAllocator - this was deleting the worker's thread death notifier in the context of a worker thread (which is only allowed from the context of the main thread).
* Added lots more smoketests
* Added --overwrite option to fzip (previously unzipping would always overwrite)
// fzip.cpp
//
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include <zipfile.h>
#include <ezgzip.h>
#include "fzip.h"
_LIT(KGzExtension, ".gz");
_LIT(KZipExtension, ".zip");
CCommandBase* CCmdZip::NewLC()
{
CCmdZip* self = new (ELeave) CCmdZip();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdZip::~CCmdZip()
{
iFileToZip.Close();
}
CCmdZip::CCmdZip() : CCommandBase(CCommandBase::EManualComplete)
{
}
const TDesC& CCmdZip::Name() const
{
_LIT(KName, "fzip");
return KName;
}
void CCmdZip::DoRunL()
{
FsL();
if (iUnzip)
{
if (!iOptions.IsPresent(&iUnzipPath))
{
iUnzipPath = Env().Pwd();
}
if (iVerbose)
{
// command-line sanity checks
if (iFileToZip.Count() > 0)
{
PrintWarning(_L("--file option is not relevant when unzipping."));
}
if (iRecurse)
{
PrintWarning(_L("--recurse option is not relevant when unzipping."));
}
}
ExpandArchiveL();
}
else
{
if (iVerbose)
{
// command-line sanity checks
if (iUnzipPath.Length() > 0)
{
PrintWarning(_L("--directory option is not relevant when zipping."));
}
}
if (iFileToZip.Count() == 0)
{
LeaveIfErr(KErrArgument, _L("Specify some files to zip up using --file option."));
}
TRAPL(CreateArchiveL(), _L("Couldn't create %S"), &iArchive);
}
if (iVerbose)
{
Printf(_L("Done\r\n"));
}
Complete(KErrNone);
}
void CCmdZip::ArgumentsL(RCommandArgumentList& aArguments)
{
_LIT(KArg1, "zipfile");
aArguments.AppendFileNameL(iArchive, KArg1);
}
void CCmdZip::OptionsL(RCommandOptionList& aOptions)
{
_LIT(KOptVerbose, "verbose");
aOptions.AppendBoolL(iVerbose, KOptVerbose);
_LIT(KOptUnzip, "unzip");
aOptions.AppendBoolL(iUnzip, KOptUnzip);
_LIT(KOptDirectory, "directory");
aOptions.AppendFileNameL(iUnzipPath, KOptDirectory);
_LIT(KOptRecurse, "recurse");
aOptions.AppendBoolL(iRecurse, KOptRecurse);
_LIT(KOptSource, "file");
aOptions.AppendFileNameL(iFileToZip, KOptSource);
_LIT(KOptCompressionType, "compression-type");
aOptions.AppendEnumL((TInt&)iCompressionType, KOptCompressionType);
_LIT(KOptOverwrite, "overwrite");
aOptions.AppendBoolL(iOverwrite, KOptOverwrite);
}
//
// COMPRESSION FUNCTIONS
//
//
// CCmdZip::CreateArchiveL
// determine which zip format to use and go ahead & create the archive
//
void CCmdZip::CreateArchiveL()
{
if (iArchive.Length() == 0)
{
iArchive = iFileToZip[0];
iArchive.Append(iCompressionType == EGZip ? KGzExtension() : KZipExtension());
}
if (iArchive.Exists(FsL()))
{
if (iOverwrite)
{
FsL().Delete(iArchive);
}
else
{
LeaveIfErr(KErrAlreadyExists, _L("File %S already exists on disk. Use --overwrite or specify a different file"), &iArchive);
}
}
if (iCompressionType == EGZip)
{
CreateGzArchiveL();
}
else
{
CreateZipArchiveL();
}
}
//
// CCmdZip::CreateGzArchiveL
// create an archive, zipping up all the specified files
//
void CCmdZip::CreateGzArchiveL()
{
if (iRecurse)
{
LeaveIfErr(KErrArgument, _L("GNU Zip format does not support recursion"));
}
if (iFileToZip.Count() > 1)
{
LeaveIfErr(KErrArgument, _L("GNU Zip format can only handle a single file"));
}
if (iVerbose)
{
Printf(_L("Creating '%S'\r\n"), &iArchive);
}
// open the input file
RFile input;
User::LeaveIfError(input.Open(FsL(), iFileToZip[0], EFileStream | EFileRead | EFileShareAny));
CleanupClosePushL(input);
CEZFileToGZip* zip = CEZFileToGZip::NewLC(FsL(), iArchive, input);
while (zip->DeflateL())
{
// do nothing
}
if (iVerbose)
{
Printf(_L("Deflating '%S'\r\n"), &iFileToZip[0]);
}
CleanupStack::PopAndDestroy(2); // zip, input
}
//
// CCmdZip::CreateZipArchiveL
// zip format archive creation
//
void CCmdZip::CreateZipArchiveL()
{
CZipItUp* zipArchive = CZipItUp::NewLC(Fs(), iArchive);
for (TInt ii = 0 ; ii < iFileToZip.Count() ; ii++)
{
TFileName2& fileName = iFileToZip[ii];
fileName.SetTypeL(Fs());
AddFileL(*zipArchive, fileName);
}
zipArchive->CreateZipL();
if (iVerbose)
{
Printf(_L("Created '%S'\r\n"), &iArchive);
}
CleanupStack::PopAndDestroy(); // zipArchive
}
//
// CCmdZip::AddFileL
// examines a file for wildcards, directories/recursion etc
// if it finds an actual file, it'll add it to the zip archive
// recursive function
//
void CCmdZip::AddFileL(CZipItUp& aZipArchive, const TFileName2& aFile)
{
if (aFile.IsDir())
{
CDir* dir;
LeaveIfErr(Fs().GetDir(aFile, KEntryAttMatchMask, EDirsLast, dir), _L("Unable to read directory '%S'"), &aFile);
CleanupStack::PushL(dir);
for (TInt ii = 0 ; ii < dir->Count() ; ii++)
{
const TEntry& entry = (*dir)[ii];
TFileName2* newFile = new(ELeave) TFileName2(entry.iName);
CleanupStack::PushL(newFile);
newFile->MakeAbsoluteL(aFile.DriveAndPath());
newFile->SetTypeL(Fs());
if (newFile->IsDir())
{
if (iRecurse)
{
AddFileL(aZipArchive, *newFile);
}
}
else
{
AddFileL(aZipArchive, *newFile);
}
CleanupStack::PopAndDestroy(newFile);
}
CleanupStack::PopAndDestroy(dir);
}
else
{
if (iVerbose)
{
Printf(_L("Adding '%S'\r\n"), &aFile);
}
aZipArchive.AddFileL(aFile);
}
}
//
// DECOMPRESSION FUNCTIONS
//
//
// CCmdZip::ExpandArchiveL
// determine which zip format to use and go ahead & expand the archive
//
void CCmdZip::ExpandArchiveL()
{
if (iCompressionType == EGZip)
{
ExpandGzArchiveL();
}
else
{
ExpandZipArchiveL();
}
}
//
// CCmdZip::ExpandGzArchiveL
// unzip an existing gzip compressed file
//
void CCmdZip::ExpandGzArchiveL()
{
// open the destination file, determine where it goes
RFile newFile;
TFileName2 dest(iUnzipPath);
if (iVerbose)
{
Printf(_L("Opening\t\t\'%S\'\r\n"), &iArchive);
}
if (iArchive.Ext().CompareF(KGzExtension) != 0)
{
LeaveIfErr(KErrArgument, _L("Compressed file must have '.gz' extension."));
}
dest.AppendComponentL(iArchive.Name());
TInt err = Fs().MkDirAll(dest);
if ((err != KErrNone) && (err != KErrAlreadyExists))
{
LeaveIfErr(err, _L("Couldn't create path '%S'"), &dest);
}
if (iOverwrite)
{
err = newFile.Replace(FsL(), dest, EFileStream | EFileRead | EFileWrite | EFileShareAny);
}
else
{
err = newFile.Create(FsL(), dest, EFileStream | EFileRead | EFileWrite | EFileShareAny);
}
LeaveIfErr(err, _L("Couldn't create file %S"), &dest);
CleanupClosePushL(newFile);
// inflate the compressed file
CEZGZipToFile* zip = CEZGZipToFile::NewLC(Fs(), iArchive, newFile);
while (zip->InflateL())
{
// do nothing
}
if (iVerbose)
{
Printf(_L("Inflating '%S'\r\n"), &dest);
}
CleanupStack::PopAndDestroy(2); // zip, newFile
}
//
// CCmdZip::ExpandZipArchiveL
// Unzip an existing archive iterating through each member file contained within the archive
//
void CCmdZip::ExpandZipArchiveL()
{
if (iVerbose)
{
Printf(_L("Opening\t\t\'%S\'\r\n"), &iArchive);
}
CZipFile* zip = NULL;
TRAPL(zip = CZipFile::NewL(Fs(), iArchive), _L("Couldn't create CZipFile for %S"), &iArchive);
CleanupStack::PushL(zip);
CZipFileMemberIterator* zipIterator = zip->GetMembersL();
CleanupStack::PushL(zipIterator);
CZipFileMember* zipMember = zipIterator->NextL();
while (zipMember)
{
CleanupStack::PushL(zipMember);
ExtractZipFileL(*zip, *zipMember);
CleanupStack::PopAndDestroy(zipMember);
zipMember = zipIterator->NextL();
}
CleanupStack::PopAndDestroy(2); // zipIterator, zip
}
//
// CCmdZip::ExtractZipFileL
// extracts a single file from within the zip archive
//
void CCmdZip::ExtractZipFileL(CZipFile& aZip, const CZipFileMember& aMember)
{
// prep. the destination file.
// note if iUnzipPath is not specified, it'll stuff the extracted file in the current directory from which fzip.exe runs
RFile newFile;
TFileName2 dest(iUnzipPath);
dest.AppendComponentL(*aMember.Name());
TInt err = Fs().MkDirAll(dest);
if ((err != KErrNone) && (err != KErrAlreadyExists))
{
LeaveIfErr(err, _L("Couldn't create directory for file %S"), &dest);
}
if (aMember.Name()->Right(1) == _L("\\")) return; // It's a directory entry, nothing more to be done
// prep. the stream
RZipFileMemberReaderStream* readStream;
aZip.GetInputStreamL(&aMember, readStream);
CleanupStack::PushL(readStream);
if (iOverwrite)
{
err = newFile.Replace(Fs(), dest, EFileShareExclusive);
}
else
{
err = newFile.Create(Fs(), dest, EFileShareExclusive);
}
LeaveIfErr(err, _L("Couldn't create file %S"), &dest);
CleanupClosePushL(newFile);
if (iVerbose)
{
Printf(_L("Inflating '%S'\r\n\tcrc: 0x%x\r\n\tcompressed size: %d\r\n\tuncompressed size: %d\r\n"), &dest, aMember.CRC32(), aMember.CompressedSize(), aMember.UncompressedSize());
}
// stream from the zip archive member into the destination file
TInt bytesRead = 0;
TInt length = KDefaultZipBufferLength; // 32Kb
if (aMember.UncompressedSize() < KDefaultZipBufferLength)
{
length = aMember.UncompressedSize();
}
HBufC8* data = HBufC8::NewLC(length);
TPtr8 ptr = data->Des();
do
{
LeaveIfErr(readStream->Read(ptr, length), _L("Error reading from zip stream"));
LeaveIfErr(newFile.Write(ptr), _L("Error writing to file %S"), &dest);
bytesRead += length;
if ((aMember.UncompressedSize() - bytesRead) < KDefaultZipBufferLength)
{
length = aMember.UncompressedSize() - bytesRead;
}
} while (length > 0);
// cleanup
CleanupStack::PopAndDestroy(3); // data, newfile, readstream
}
EXE_BOILER_PLATE(CCmdZip)