diff -r e20de85af2ee -r ce057bb09d0b genericopenlibs/openenvcore/backend/src/corebackend/fdesc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/genericopenlibs/openenvcore/backend/src/corebackend/fdesc.cpp Fri Jun 04 16:20:51 2010 +0100 @@ -0,0 +1,1848 @@ +/* +* Copyright (c) 1997-2009 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: +* +*/ + + +#include +#include +#include // for struct stat +#include +#include // for ENOTSOCK +#include +#include +#include +#include //for LLONG_MAX and INT_MAX +#ifdef SYMBIAN_OE_LIBRT +#include +#endif// SYMBIAN_OE_LIBRT +#include "sysreent.h" +#include "systemspecialfilercg.h" +#include "fdesc.h" +#include "lposix.h" +#include "ltime.h" + + + +/* +Temp directory, this should be checked later +*/ +#ifdef WIDEP_tmpdir +#undef WIDEP_tmpdir +#define WIDEP_tmpdir L"/System/temp/" +#endif //WIDEP_tmpdir + + + +CFileDescBase::CFileDescBase( TUint aFcntl, TUint32 aFdAttrib ) : + iReadTimeout(-1), iFcntlFlag(aFcntl), iFdAttrib(aFdAttrib), iPollErr(KErrNone) + { + } +TInt CFileDescBase::SetAtt(TUint /*aSetAttMask*/, TUint /*aClearAttMask*/) + { + return 0; + } + +// A CFileDescBase factory function, for "named" file-like objects +CFileDescBase* CFileDescBase::Open(const wchar_t* name, int mode, int perms, TInt& err) + { + err = KErrNone; + CFileDescBase* ret = NULL; + + if(WcsCmp(name, L"CON:") == 0) + { + ret = new CTtyDesc; // NB. This won't be the default stdin/stdout/stderr console + } + else if(WcsCmp(name, L"NUL:") == 0) + { + ret = new CFileDescBase; + } + else if((WcsCmp(name, L"TMP:") == 0) || (mode & O_TMPFILE)) + { + CTempFileDesc* tmp = new CTempFileDesc; + if(tmp != NULL) + { + err = tmp->Open(name, mode); + if(err != KErrNone) + { + delete tmp; + tmp = NULL; + } + } + ret = tmp; + } +#ifdef SYMBIAN_OE_LIBRT + else if(mode & O_SHMFLG) + { + CSharedMemDesc* shm= new CSharedMemDesc; + if(shm != NULL) + { + err = shm->Open(name, mode, perms); + if(err != KErrNone) + { + delete shm; + shm = NULL; + } + } + ret = shm; + } + #endif //SYMBIAN_OE_LIBRT + else if ((L'C' == name[0]) && (L'O' == name[1]) && (L'M' == name[2]) && (L':' == name[4]) && ((name[3] >= L'1') && (name[3] <= L'9')) || + (L'I' == name[0]) && (L'R' == name[1]) && (L'C' == name[2]) && (L'O' == name[3]) && (L'M' == name[4]) && (L':' == name[6]) && ((name[5] >= L'1') && (name[5] <= L'9'))) + { + CSerialDesc* com = new CSerialDesc; + if (com != NULL) + { + err = com->Open(name, mode, perms); + if(err != KErrNone) + { + delete com; + com = NULL; + } + } + ret = com; + } + else //It's a special file, directory or normal file + { + RFs& rfs = Backend()->FileSession(); + TUint attribval; + TFullName fullName; + err = GetFullFile(fullName, (const TText16*)name, rfs); + if(err != KErrNone) + return NULL; + int ret1 = rfs.Att(fullName, attribval); + if (ret1 == 0 && ((attribval & (KEntryAttHidden | KEntryAttSystem))== (KEntryAttHidden | KEntryAttSystem))) + { + TSpecialFileType fileType = _SystemSpecialFileBasedFilePath(name, err, rfs); + if(fileType == EFileTypeMkFifo) //special file, FIFO + { + ret = CFileTable::FifoOpen(name, mode, perms, err); + } + else if(fileType == EFileTypeSymLink) //special file, symlink + { + ret = CFileTable::LinkOpen(name, mode, perms, err, rfs); + } + } + else //normal file or directory + { + //Try opening as a file + CFileDesc* file = new CFileDesc; + if(file != NULL) + { + err = file->Open(rfs, fullName, mode, perms); + if(err != KErrNone) + { + delete file; + file = NULL; + } + } + ret = file; + + //Check if it is directory, if the open as file failed + if(err != KErrNone && CheckIfDirectory(fullName, rfs)) + { + CDirectoryDesc* dir = new CDirectoryDesc; + if(dir != NULL) + { + err = dir->Open(rfs, fullName, mode, perms); + if(err != KErrNone) + { + delete dir; + dir = NULL; + } + } + ret = dir; + } + } + } + + if(err == KErrNone && ret == NULL) + { + err = KErrNoMemory; + } + + return ret; + } + +//Check if a path corresponds to a directory. This is a helper function +//for CFileDescBase::Open() +TBool CFileDescBase::CheckIfDirectory(const TDesC& aPath, RFs& aFs) + { + //Check whether its a Drive Name + if(KMaxDriveName+1 == aPath.Length()) + { + if(RFs::IsValidDrive(TDriveUnit(aPath))) + { + return ETrue; + } + } + //Now check whether it is a directory + else + { + TEntry entry; + if(aFs.Entry(aPath, entry) == KErrNone) + { + if(entry.IsDir()) + { + return ETrue; + } + } + } + + return EFalse; + } + +// Useful default implementations for CFileDescBase virtual functions. +// Function to be re-implemented in a child class which can seek. +TInt CFileDescBase::LSeek (off_t& offset, int) + { + // minimal implementation for devices which can't seek + offset=-1; + return ESPIPE; + } + +void CFileDescBase::Read (TDes8& aBuf, TRequestStatus& aStatus) + { + // minimal implementation for /dev/null + aBuf.Zero(); // set length to zero + TRequestStatus* sp=&aStatus; + User::RequestComplete(sp,KErrNone); + } + +void CFileDescBase::ReadCancel() {} + +TInt CFileDescBase::ReadCompletion (TDes8& /*aBuf*/, TInt aStatus) + { + return aStatus; + } + + +TInt CFileDescBase::FStat (struct stat *st) + { + // minimal implementation: + // I am a character device about which little is known + st->st_mode = S_IFCHR; + st->st_blksize=0; + return KErrNone; + } + +void CFileDescBase::Complete (TRequestStatus& aStatus, TInt aResult) + { + TRequestStatus* sp=&aStatus; + User::RequestComplete(sp,aResult); + } + +void CFileDescBase::Write (TDes8& /*aBuf*/, TRequestStatus& aStatus) + { + // minimal implementation for /dev/null + // we will claim to have written all of the data + Complete(aStatus,KErrNone); + } + +void CFileDescBase::WriteCancel() {} + +TInt CFileDescBase::WriteCompletion (TDes8& /*aBuf*/, TInt aStatus) + { + return aStatus; + } + +void CFileDescBase::Sync(TRequestStatus& aStatus) + { + // minimal implementation for /dev/null + Complete(aStatus,KErrNone); + } + +void CFileDescBase::SyncCancel() {} + +void CFileDescBase::Ioctl(int /*aCmd*/, void* /*aParam*/, TRequestStatus& aStatus) + { + // minimal implementation for /dev/null and other synchronous devices + Complete(aStatus,KErrNone); + } + +void CFileDescBase::IoctlCancel() + { + return; // suitable for all synchronous ioctls + } + +TInt CFileDescBase::IoctlCompletion(int aCmd, void* aParam, TInt aStatus) + { + TInt ret=aStatus; + if (ret!=KErrNone) + return ret; + int *param = reinterpret_cast (aParam); + switch ((unsigned)aCmd) + { + case FIONREAD: + case E32IONREAD: + *param=0; // claim that no data is available + break; + case E32IOSELECT: + *param=(*param)&(E32SELECT_READ|E32SELECT_WRITE); // but don't block + break; + default: + ret=KErrNotSupported; + break; + } + return ret; + } + +// A CFileDescBase factory function, for socket objects + +CFileDescBase* CFileDescBase::Socket(RSocketServ& aSs, int family, int style, int protocol, TInt& err) + { + // connect to the Socket Server if necessary + if (aSs.Handle()==0) + { + err=aSs.Connect(TUint(-1)); // allow arbitrary number of requests + if (err) + return 0; + else + { + err = aSs.ShareAuto(); + if (err) + return 0; + } + } + CSockDescBase *socketBase = NULL; + if (family == AF_LOCAL || family == PF_LOCAL || family == AF_UNIX) + { + + //coverity[alloc_fn] + //coverity[assign] + + socketBase = new CFileSocketDesc; + } + else + { + socketBase = new CSocketDesc; + } + + if (!socketBase) + { + err=KErrNoMemory; + return 0; + } + err = socketBase->Socket(aSs,family,style,protocol); + + if (err) + { + delete socketBase; + if (err == KErrBadName) // Some mismatch in family-style-protocol + { + err = EPROTONOSUPPORT; + } + //coverity[memory_leak] + return 0; + } + return socketBase; + } + +// minimal implementation of sockets, useful for all non-socket descriptors + +void CFileDescBase::RecvFrom(TDes8& /*aDesc*/, TSockAddr& /*from*/, int /*flags*/, TRequestStatus& aStatus) + { + // minimal implementation + Complete(aStatus,ENOTSOCK); + } + +void CFileDescBase::RecvFromCancel() {} + +TInt CFileDescBase::CompletionStatus (TInt& /*aLength*/, TInt aStatus) + { + return aStatus; + } + +void CFileDescBase::SendTo(TDes8& /*aDesc*/, const struct sockaddr* /* anAddr*/, unsigned long /*aAddrLen*/, int /*flags*/, TRequestStatus& aStatus) + { + // minimal implementation + Complete(aStatus,ENOTSOCK); + } + +void CFileDescBase::SendToCancel() {} + +void CFileDescBase::Shutdown(TUint /*aHow*/,TRequestStatus& aStatus) + { + // minimal implementation + Complete(aStatus,ENOTSOCK); + } + +void CFileDescBase::ShutdownCancel() {} + +TInt CFileDescBase::Bind(const struct sockaddr* /*addr*/, unsigned long /*size*/) + { + return ENOTSOCK; + } + +TInt CFileDescBase::Listen(TUint /*qSize*/) + { + return ENOTSOCK; + } + +void CFileDescBase::Accept(CFileDescBase*& /*aNewSocket*/, TRequestStatus& aStatus, RSocketServ& /*aSs*/, TSockAddr * /*aAddr*/) + { + // minimal implementation + Complete(aStatus,ENOTSOCK); + } + +void CFileDescBase::AcceptCancel() {} + +void CFileDescBase::Connect(const struct sockaddr* /*anAddr*/,unsigned long /*aSize*/,TRequestStatus& aStatus) + { + // minimal implementation + Complete(aStatus,ENOTSOCK); + User::WaitForRequest(aStatus); + } + +void CFileDescBase::ConnectCancel() {} + +TBool CFileDescBase::GetConnectionProgress() + { + return EFalse; + } + +void CFileDescBase::SetConnectionProgress( TBool /* aInProgress */ ) {} + +TInt CFileDescBase::SockName(int /*anEnd*/, struct sockaddr* /*anAddr*/,unsigned long* /*aSize*/) + { + return ENOTSOCK; + } + +TInt CFileDescBase::GetSockOpt(TInt /*anOptionName*/,TInt /*anOptionLevel*/,TDes8& /*anOption*/) + { + return ENOTSOCK; + } + +TInt CFileDescBase::SetSockOpt(TInt /*anOptionName*/,TInt /*anOptionLevel*/,TDesC8& /*anOption*/) + { + return ENOTSOCK; + } + +// ----------------------------------------------------------------------------- +// CFileDescBase::Fcntl +// Minimal Implementation for fcntl +// ----------------------------------------------------------------------------- +// +TInt CFileDescBase::Fcntl(TUint /*anArg*/, TUint aCmd) + { + // minimal implementation: + if(aCmd == F_GETFL) + { + return KErrNotFound; + } + return KErrNotSupported; + } + +// ----------------------------------------------------------------------------- +// CFileDescBase::Poll +// Checks the file for ready to write/read and exception status +// ----------------------------------------------------------------------------- +// +TInt CFileDescBase::Poll(TPollMode /*aMode*/,TBool& aStatus,TInt& /*aErrno*/) + { + // always return True, let the derived filedescriptors override + aStatus = ETrue; + return 0; + } + +// ----------------------------------------------------------------------------- +// CFileDescBase::Poll - Overloaded +// Synchronous non-blocking call that returns current state of the file descriptor +// ----------------------------------------------------------------------------- +// +TInt CFileDescBase::Poll(TUint aEvents) + { + // We return that the file descriptor is select true for ready to read, + // ready to write and error conditions. + // Let derived file descriptors override as approp. + TInt readyEvents = 0; + + if (aEvents & EReadyForReading) + { + readyEvents = EReadyForReading; + } + if (aEvents & EReadyForWriting) + { + readyEvents |= EReadyForWriting; + } + if (aEvents & EAnyException) + { + readyEvents |= EAnyException; + } + + return readyEvents; + } + +// ----------------------------------------------------------------------------- +// CFileDescBase::NotifyActivity +// Registers with the approp. underlying subsystem for read/write/except notifications +// ----------------------------------------------------------------------------- +// +TInt CFileDescBase::NotifyActivity(TUint /*aEvents*/, TRequestStatus& /*aRequest*/, TTimeIntervalMicroSeconds32 /*timeout*/) + { + // We return KErrCompletion indicating that this activity is complete for + // this descriptor. + // Let derived file descriptors override as approp. + return KErrCompletion; + } + +// ----------------------------------------------------------------------------- +// CFileDescBase::TweakWatchedEvents +// Requests for fd behaviour specific additional events +// ----------------------------------------------------------------------------- +// +void CFileDescBase::TweakWatchedEvents(TUint& /*events*/) + { + // No implementation required + // This version is used for both Redir and pipe desc, it is overridden + // by socket + } + +// ----------------------------------------------------------------------------- +// CFileDescBase::TweakReadyEvents +// Prepares the fd behaviours specific output events +// ----------------------------------------------------------------------------- +// +TInt CFileDescBase::TweakReadyEvents(TInt /*errval*/) + { + return KErrNone; + } + +// CFileDescBase::CancelNotify +// Cancel an outstanding request for read/write/except notifications +// ----------------------------------------------------------------------------- +// +void CFileDescBase::CancelNotify() + { + // do nothing + return; + } + + +// Generic (non-virtual) handling for Close +EXPORT_C TInt CFileDescBase::Close() + { + TInt err = KErrNone; + //Decrement the dup count and mark this FD as invalid if dupcount is 0 + if ( --iDupCount < 0 ) + { + iFdAttrib |= KInvalidFd; + //delete this FD only if its not mmaped and being used + if(!(iFdAttrib & KMMapedFd)) + { + err=FinalClose(); + //Release the Lock now + delete this; + } + } + return err; + } + +TInt CFileDescBase::FinalClose() + { + return KErrNone; + } + +void CFileDescBase::SetFids(void *) + { + // nada (virtual) + } + +// Simple implementation of File handling +static int MapMode(int aMode, TUint& fMode) + { + // EPOC32 doesn't support Write-Only + if (aMode & (O_WRONLY|O_RDWR)) + { + fMode = EFileWrite; + } + else + { + fMode = EFileRead; + } + + fMode |= (aMode & O_TEXT) ? EFileStreamText : EFileStream; + fMode |= EFileShareReadersOrWriters; + + return aMode & (O_CREAT|O_TRUNC|O_APPEND|O_EXCL|O_EXLOCK); + } + +CFileDesc::CFileDesc() + :CFileDescBase(), iSize(EBufferSize), iExt(-1) + {} + +void CFileDesc::SetState(const TDes& params) + { + TFileName name; + iFile.FullName(name); + iDrive = (TInt16)TDriveUnit(name); + + TLex lexr(params); + lexr.Val(iPos); + lexr.Inc(); + lexr.Val(iExt); + lexr.Inc(); + lexr.Val(iFcntlFlag); + lexr.Inc(); + lexr.Val(iFdAttrib, EDecimal); + lexr.Inc(); + lexr.Val(iPos); + lexr.Inc(); + lexr.Val(iExt); + lexr.Inc(); + lexr.Val(iSize); + + } + +CFileDesc::~CFileDesc() + { + iFile.Close(); + if(iBuffer) + { + RHeap* oldHeap = User::SwitchHeap(Backend()->Heap()); + delete [] iBuffer; + User::SwitchHeap(oldHeap); + } + } + +TInt CFileDesc::FinalClose() + { + TInt err = DoSync(); + iLock.Close(); + return err; + } + +TInt CFileDesc::Open(RFs& aSession, const TDesC& aName, int mode, int perms) + { + TInt err; + TUint fMode; + + iDrive=(TInt16)TDriveUnit(aName); + + // Create = make new file, can return KErrAlreadyExists + // Open = open an existing file, can return KErrPathNotFound or KErrNotFound + // Replace = open a new file, zapping the existing one if necessary + + int mapped=MapMode(mode, fMode); + // if the file is in \sys, use EFileShareReadersOnly not EFileShareReadersOrWriters + TParsePtrC pars(aName); + if (pars.Path().FindF(_L("\\SYS\\")) == 0) + { + fMode &= ~EFileShareReadersOrWriters; + fMode |= EFileShareReadersOnly; + } + + // if the file is in \resource, dont use EFileShareReadersOrWriters + if (pars.Path().FindF(_L("\\resource\\")) == 0) + { + fMode &= ~EFileShareReadersOrWriters; + fMode |= EFileShareReadersOnly; + } + + //Set iFcntlFlag flag + iFcntlFlag = mode & O_ACCMODE; + + if(mode & O_APPEND) + { + iFcntlFlag |= O_APPEND; + } + + TInt fileMode = 0; + TBool created = EFalse; + //store the open modes in the file descriptor object + + switch(perms & (S_IRUSR | S_IWUSR )) + { + case S_IRUSR | S_IWUSR: //owner read write + case S_IWUSR : //owner write + { + break; + } + case S_IRUSR: //owner read + { + fileMode = KEntryAttReadOnly; + break; + } + default: + { + break; + } + } + + switch (mapped) + { + case O_CREAT|O_EXCL: //For O_EXCL if file exists then return error + err = iFile.Create(aSession, aName, fMode); + if(err) + { + return err; + } + created = ETrue ; + break; + case O_CREAT|O_TRUNC: + err = iFile.Replace(aSession, aName, fMode); + if(!err) + { + created = ETrue; + } + break; + case O_TRUNC: + err = iFile.Open(aSession, aName, fMode); + if(!err) + err = iFile.SetSize(0); + break; + case O_CREAT|O_EXCL|O_APPEND: //if file exists then return error + err = iFile.Create(aSession, aName, fMode); + if(err) + { + return err; + } + created = ETrue ; + break; + case O_CREAT|O_EXCL|O_TRUNC: //if file exists then return error + err = iFile.Create(aSession, aName, fMode); + if(!err) + { + err = iFile.SetSize(0); + created = ETrue ; + } + else + { + return err; + } + break; + case O_EXLOCK: //emulating exclusive locks + err = iFile.Open(aSession, aName, fMode); + if(err == KErrNone) + { + FSIZE fileSize = 0; + err = iFile.Size(fileSize); + if(fileSize <= 0 ) + return KErrNotSupported; + + if(err == KErrNone) + { + err = iFile.Lock(0, fileSize); + } + } + + if(err != KErrNone) + { + return err; + } + break; + // Everything else is assumed to mean open existing file, + // If the file isn't there, O_CREAT implies that we should make it + default: + err = iFile.Open(aSession, aName, fMode); + if (err == KErrNotFound && (mapped & O_CREAT)) + { + err = iFile.Create(aSession, aName, fMode); + if(!err) + { + created = ETrue; + } + + } + if((err == KErrArgument) &&(mode == (O_CREAT | O_RDONLY))) + { + TUint CrMode = EFileShareReadersOrWriters | EFileWrite ; + CrMode |= (mode & O_TEXT) ? EFileStreamText : EFileStream; + err = iFile.Create(aSession , aName , CrMode); + + if(!err) + { + created = ETrue; + iFile.Close() ; + err = iFile.Open(aSession, aName , fMode); + } + } + + if (err == KErrNone && (mapped & O_APPEND)) + { + iPos = Ext(); + if (iPos < 0) + err = iPos; + } + break; + + } + if ((mode & O_BUFFERED) == 0) + iSize = 0; + + //If File is to be opened for O_CREAT | O_RDONLY, set the corresponding attributes + if(created && fileMode) + { + err = iFile.SetAtt(fileMode, 0) ; + } + + if (!err) + { + err = Alloc(); + } + + if(err == KErrNone) + { + err = CreateLock(); + } + + return err; + } + +TInt CFileDesc::LSeek (off_t& offset, int whence) + { + //return if its an invalid fd + //This scenario comes when the file is closed, but mmap still exists + if(iFdAttrib & KInvalidFd) + { + return KErrBadHandle; + } + iLock.Wait(); + FSIZE pos=offset; + FSIZE ext=Ext(); + if (ext < 0) + { + iLock.Signal(); + return ext; + } + switch (whence) + { + case SEEK_SET: + break; + case SEEK_CUR: + pos += Pos(); + break; + case SEEK_END: + pos += ext; + break; + default: + { + iLock.Signal(); + return KErrArgument; + } + } + + TInt ret = KErrNone; + if (pos < 0) + { + iLock.Signal(); + return KErrArgument; + } + else if (pos >= ext) + { + ret = Flush(); + if (!ret) + { + iState = EAlloc; + } + } + + switch (iState) + { + case EAlloc: + iPos = pos; + break; + case EReading: + { + FSIZE lag = iPos - pos; + if (lag >= 0 && lag <= (iEnd - iBuffer)) + iPtr = iEnd - lag; + else + { + iPtr = iEnd; + iPos = pos; + } + } + break; + case EWriting: + if (pos != Pos()) + { + ret = Flush(); + if (ret != KErrNone) + { + iLock.Signal(); + return ret; + } + iPos = pos; + } + break; + default: + { + //Do nothing + } + } + offset = pos; + iLock.Signal(); + return ret; + } + +void CFileDesc::MapStat(struct stat& st, const TTime& aModTime, TUint& aAttr, const mode_t aMode) + { + if ( aMode == S_IFREG) + { + st.st_mode = (aAttr&KEntryAttDir) ? S_IFDIR: S_IFREG; + } + else + { + st.st_mode = aMode; + } + + if ((aAttr&KEntryAttReadOnly)) + { + st.st_mode |= S_IRUSR; + } + else + { + st.st_mode = st.st_mode | S_IWUSR | S_IRUSR; + } + + st.st_nlink = (S_IFLNK == st.st_mode) ? 2 : 1; + TTimeIntervalSeconds res; + const TTime KEpocTime(MAKE_TINT64(0x00dcddb3,0x0f2f8000)); // 00:00, Jan 1st 1970 + if(aModTime.SecondsFrom(KEpocTime, res)) + { + st.st_mtime = -1; + st.st_atime = -1 ; + st.st_ctime = -1; + } + else + { + st.st_mtime = res.Int(); + st.st_ctime = st.st_atime = st.st_mtime ; //here modification and access time are same + } + st.st_blksize=512; + } + +TInt CFileDesc::FStat (struct stat* st) + { + //return if its an invalid fd + if(iFdAttrib & KInvalidFd) + { + return KErrBadHandle; + } + TInt err; + TUint att; + TTime modtime; + + err = iFile.Att(att); + if (!err) + { + err = iFile.Modified(modtime); + if (!err) + { + FSIZE ext=Ext(); + if (ext >= 0) + { + st->st_size = ext; + st->st_dev = st->st_rdev = iDrive; + MapStat(*st, modtime, att); + return 0; + } + else + err = ext; + } + } + return err; + } + +TInt CFileDesc::SetAtt(TUint aSetAttMask, TUint aClearAttMask) + { + return iFile.SetAtt(aSetAttMask , aClearAttMask) ; + } + +TInt CFileDesc::Alloc() + { + if (iSize) + { + //Delete if iBuffer is holding some memory already + if (iBuffer) + { + delete [] iBuffer; + } + iBuffer = new TUint8[iSize]; + if (iBuffer == 0) + return KErrNoMemory; + } + return KErrNone; + } + +TInt CFileDesc::FileRead(TUint8* aPtr,TInt aLength) + { + TPtr8 ptr(aPtr,aLength); + TInt r=iFile.Read(iPos,ptr); + if (r == KErrNone) + { + r = ptr.Length(); + iPos += r; + if (r < aLength) + iExt = iPos; + } + return r; + } + +TInt CFileDesc::FileWrite(TUint8* aPtr,TInt aLength) + { + TPtrC8 ptr(aPtr,aLength); + if (iExt >= 0) + { + if (iPos > iExt) + { + iFile.SetSize(iPos); + } + } + + // Check if the specified file is opened in O_APPEND + // mode and set right the file write position + if(iFcntlFlag & O_APPEND) + { + FSIZE bytes=0; + TInt ret = iFile.Size(bytes); + if (ret < 0) + return ret; + iPos = Max(bytes, Pos()); + } + + TInt r = iFile.Write(iPos,ptr); + if (r == KErrNone) + { + r = ptr.Length(); + iPos += aLength; + if (iPos > iExt && iExt >= 0) + iExt = iPos; + } + return r; + } + +TInt CFileDesc::Flush() + { + if (iPtr > iBuffer) + { + TInt r = FileWrite(iBuffer, iPtr-iBuffer); + if (r < 0) + return r; + iPtr = iBuffer; + } + return KErrNone; + } + +TInt CFileDesc::DoRead (TDes8& aDesc) + { + if (iState != EReading) + { + if (iState != EAlloc) + { + TInt ret = Flush(); + if (ret != KErrNone) + { + return ret; + } + } + iState = EReading; + iPtr = iEnd = iBuffer; + } + + TUint8* p = (TUint8*) aDesc.Ptr(); + TInt max = aDesc.MaxLength(); + TInt avail = iEnd - iPtr; + TInt len = Min(max, avail); + if (len > 0) + { + p = Mem::Copy(p, iPtr, len); + iPtr += len; + max -= len; + } + if (max >= iSize) + { + TInt ret = FileRead(p, max); + if (ret < 0) + return ret; + p += ret; + } + else if (max > 0) + { + TInt ret = FileRead(iBuffer, Min(max + EReadAhead, iSize)); + if (ret < 0) + return ret; + len = Min(max, ret); + p = Mem::Copy(p, iBuffer, len); + iPtr = iBuffer + len; + iEnd = iBuffer + ret; + } + aDesc.SetLength(p-aDesc.Ptr()); + return aDesc.Length(); + } + +void CFileDesc::Read (TDes8& aDesc, TRequestStatus& aStatus) + { + //return if its an invalid fd + if(iFdAttrib & KInvalidFd) + { + Complete(aStatus, KErrBadHandle); + return; + } + //Acquire the Lock before read and release it later + iLock.Wait(); + Complete(aStatus,DoRead(aDesc)); + iLock.Signal(); + } + +TInt CFileDesc::DoWrite (TDes8& aDesc) + { + if (iState != EWriting) + { + if (iState != EAlloc) + { + iPos -= iEnd - iPtr; + } + + iState = EWriting; + iPtr = iBuffer; + iEnd = iBuffer + iSize; + } + + TUint8* p = (TUint8*) aDesc.Ptr(); + TInt max = aDesc.Length(); + TInt avail = iEnd - iPtr; + TInt len = Min(max, avail); + if (len > 0) + { + iPtr = Mem::Copy(iPtr, p, len); + p += len; + max -= len; + } + if (max == 0) + return len; + TInt r=Flush(); + if (r < 0) + return r; + if (max >= iSize) + return len + FileWrite(p, max); + iPtr = Mem::Copy(iPtr, p, max); + return len + max; + } + +void CFileDesc::Write(TDes8& aDesc, TRequestStatus& aStatus) + { + //return if its an invalid fd + if(iFdAttrib & KInvalidFd) + { + Complete(aStatus, KErrBadHandle); + return; + } + //Acquire the Lock before write and release it later + iLock.Wait(); + Complete(aStatus,DoWrite(aDesc)); + iLock.Signal(); + } + +TInt CFileDesc::DoSync() + { + if (iState == EWriting) + { + TInt ret = Flush(); + if (ret < 0) + return ret; + } + return iFile.Flush(); + } + +void CFileDesc::Sync(TRequestStatus& aStatus) + { + iLock.Wait(); + Complete(aStatus,DoSync()); + iLock.Signal(); + } + +FSIZE CFileDesc::Pos() + { + FSIZE pos = iPos; + if (iState == EReading) + pos -= (iEnd - iPtr); + else if (iState == EWriting) + pos += (iPtr - iBuffer); + return pos; + } + +FSIZE CFileDesc::Ext() + { + TInt r = iFile.Size(iExt); + if (r < 0) + return r; + return iExt; + } + +TInt CFileDesc::IoctlCompletion(int aCmd, void* aParam, TInt aStatus) + { + TInt ret=aStatus; + if (ret!=KErrNone) + return ret; + // some useful sums about the current state of the file + FSIZE curoff = Pos(); + FSIZE size = Ext(); + if (size < 0) + ret = size; + int *param=reinterpret_cast (aParam); + switch ((unsigned)aCmd) + { + case FIONREAD: + case E32IONREAD: + if (ret==KErrNone) + *param=(size-curoff); + break; + case E32IOSELECT: + { + int mask=E32SELECT_WRITE; + if ((size-curoff)>0) + mask |= E32SELECT_READ; + *param=(*param)&mask; // but don't block + } + break; + default: + ret=KErrNotSupported; + break; + } + return ret; + } + + +#if defined(SYMBIAN_OE_LARGE_FILE_SUPPORT) && !defined(SYMBIAN_OE_NO_LFS) +// this needs to be corrected once the api which gives the large file size is available. +//#define MAX_SIZE LLONG_MAX /* 2^63-1 - MAX file size */ +#define MAX_SIZE INT_MAX /* 2^31-1 - MAX file size */ +#else +#define MAX_SIZE INT_MAX /* 2^31-1 - MAX file size */ +#endif //SYMBIAN_OE_LARGE_FILE_SUPPORT && !SYMBIAN_OE_NO_LFS + +TInt CFileDesc::ProcessLockParams(FSIZE& pos, FSIZE& lock_len, TInt& lock_type, struct flock* lock) + { + TInt retVal=0; + lock_type = lock->l_type; + if(!lock->l_len) //if len = 0 then lock must be extended to the system limit for max file size + { + lock_len=MAX_SIZE; + } + else //len argument is non-zero + { + lock_len = lock->l_len; + } + pos =lock->l_start; //offset + switch( lock->l_whence ) + { + case SEEK_SET: + + if(pos<0) + { + retVal = KErrArgument; + return retVal; + } + else + break; + case SEEK_CUR: + pos += iPos; //current position + offset + break; + case SEEK_END: + retVal = iFile.Size(pos); + switch( retVal) + { + case KErrNone: + pos += lock->l_start; //file size + ofset + break; + default: + return retVal; + } + + if(pos<0) + { + retVal = KErrArgument; + return retVal; + } + break; + default: + retVal = KErrArgument; //invalid argument + return retVal; + } + + if( lock_len < 0) + { + pos += lock_len; + lock_len = -lock_len; + } + return retVal; + } +// ----------------------------------------------------------------------------- +// CFileDesc::Fcntl +// Symbian File Specific Implementation for fcntl +// There is no mapping from Symbian RFile for File fcntl. +// This implementation supports fcntl with F_SETFL and F_GETFL as cmd +// We can set the Flag as Blocking or Non-Blocking. +// ----------------------------------------------------------------------------- +// +TInt CFileDesc::Fcntl(TUint anArg, TUint aCmd) + { + struct flock *lock = NULL; + FSIZE pos = 0,lock_len = -1; + TInt lock_type = -1; + //return if its an invalid fd + if(iFdAttrib & KInvalidFd) + { + return KErrBadHandle; + } + TInt retVal = KErrNone; + //fcntl supports only F_SETFL and F_GETFL for Non-Blocking I/O + //If aCmd and anArg does not match these, return with Error + switch( aCmd ) + { + case F_SETFL: + { + //Set the fcntl Flag + if((anArg == O_APPEND) || (anArg == O_NONBLOCK)) + { + iFcntlFlag |= anArg ; + } + retVal = 0 ; + break; + } + case F_GETFL: + { + //Return fcntl flag + retVal = iFcntlFlag; + break; + } + case F_GETFD: + { + if(iFdAttrib & KCloseonExec) + { + retVal = 1; + } + break; + } + case F_SETFD: + { + if(anArg == 1) + { + iFdAttrib |= SET_CLOSE_ON_EXEC_FLG; // (1 << 2) ; + retVal = anArg; + } + else if(anArg == 0 ) + { + iFdAttrib &= ~SET_CLOSE_ON_EXEC_FLG; //(1 << 2) ; + retVal = anArg; + } + else + { + retVal = KErrArgument; //return invalid argument + } + break; + } + case F_GETLK: + { + lock = (struct flock*)anArg; + retVal=ProcessLockParams(pos, lock_len, lock_type, lock); + if(retVal) + return retVal; + switch( lock_type) + { + case F_WRLCK: + retVal = iFile.Lock(pos ,lock_len); //try to lock the region. + if (retVal == KErrNone) + { + retVal = iFile.UnLock(pos ,lock_len); //if previous lock() is successful then unlock the region + lock->l_type = F_UNLCK; //indication that region can be locked + } + else + { + retVal = KErrNone; //region cant be lock. return success, but don't change lock->l_type + } + break; + default: + retVal = KErrArgument; + } + break; + } + case F_SETLK: + { + lock = (struct flock*)anArg; + retVal=ProcessLockParams(pos, lock_len, lock_type, lock); + if(retVal) + return retVal; + switch( lock_type) + { + case F_WRLCK: + retVal = iFile.Lock(pos ,lock_len); //try to lock without waiting + break; + case F_UNLCK: + retVal = iFile.UnLock(pos ,lock_len); //try to unlock without waiting + break; + case F_RDLCK: + retVal = KErrNotSupported; + + default: + retVal = KErrArgument; //return invalid argument + } + break; + } + default: + retVal = KErrNotSupported; + } + return retVal; + } + +// ----------------------------------------------------------------------------- +// CFileDesc::Truncate +// Symbian File Specific Implementation for Truncate +// This will truncate the file which is opened in write mode +// ----------------------------------------------------------------------------- +// +TInt CFileDesc::Truncate(off_t anOffset) + { + TInt retVal; + //return if its an invalid fd + if(iFdAttrib & KInvalidFd) + { + return KErrBadHandle; + } + iExt = anOffset; + retVal = iFile.SetSize(anOffset); + if (retVal == KErrNotSupported) + { + return KErrArgument;//to work around RFile64::SetSize() return value + } + return retVal; + } + +// Extra support for temporary files +TInt CTempFileDesc::Open(const wchar_t* aName, TInt mode) + { + iSession = Backend()->FileSession(); + + TFileName filePath; + if (mode & O_TMPFILE) //from tmpfile() + { + //obtain original mode for tmpfile() + mode &= (~O_TMPFILE); + filePath.Copy((const TText*)aName); + } + else //for "TMP:" + { + TParse path; + TInt err = GetFullPath(path, (const TText16*)WIDEP_tmpdir, NULL); + if (err != KErrNone) + { + return err; + } + filePath.Copy(path.DriveAndPath()); + } + + if((mode & O_BUFFERED) == 0) + { + setSize(0); + } + iFcntlFlag = mode & O_ACCMODE;//setting the fcntl flag + TInt ret = Alloc(); + if (ret != KErrNone) + { + return ret; + } + TFileName aPathName; + aPathName.Append(iSession.GetSystemDriveChar()); + aPathName.Append(TChar(KDriveDelimiter)); + aPathName.Append(_L("\\System\\temp")); + if (filePath.Find(aPathName) == 0) + { + ret = iSession.MkDir(filePath); + if (ret != KErrNone && ret != KErrAlreadyExists) + { + return ret; + } + else + { + ret = iFile.Temp(iSession, filePath, iName, EFileShareReadersOrWriters); + } + } + else + { + ret = iFile.Create(iSession, filePath, EFileShareReadersOrWriters); + } + return ret; + } + +TInt CTempFileDesc::FinalClose() + { + TInt ret = iFile.FullName(iName); + if (ret != KErrNone) + { + return ret; + } + iFile.Close(); + return iSession.Delete(iName); + } + +#ifdef SYMBIAN_OE_LIBRT +// ----------------------------------------------------------------------------- +// CSharedMemDesc::CSharedMemDesc : Constructor +// Constructs sharedmemory Descriptor +// ----------------------------------------------------------------------------- +CSharedMemDesc::CSharedMemDesc() + { + iLock.CreateLocal(); + } + +// ----------------------------------------------------------------------------- +// CSharedMemDesc::CSharedMemDesc : Destructor +// Destructor for sharedmemory Descriptor +// ----------------------------------------------------------------------------- +CSharedMemDesc::~CSharedMemDesc() + { + iLock.Close(); + } + +// ----------------------------------------------------------------------------- +// CSharedMemDesc::Open +// Gives sharedmemory Descriptor +// ----------------------------------------------------------------------------- +TInt CSharedMemDesc::Open(const wchar_t* aName, int mode, int perms) + { + int aerr = 0, err =0; + void* ptr = NULL; + TInt shmkey = 0; + TInt shmid = 0; + struct shmid_ds *buf = NULL; + + mode &= (~O_SHMFLG); + if(mode == O_WRONLY) + { + return KErrNone; + } + + TFileName shrdmemname; + shrdmemname.Copy((const TText*)aName); + + iPerms = perms; + iFcntlFlag = mode & O_ACCMODE; + shmkey = GeneratePathKey(shrdmemname); + switch (mode) + { + case O_CREAT: + case O_CREAT|O_RDWR: + shmid = Backend()->iIpcS.shmget(shmkey, SHM_CHUNKSIZE, IPC_CREAT|perms, aerr); + if (shmid == -1) + { + err = aerr; + return err; + } + break; + case O_TRUNC: + case O_TRUNC|O_RDWR: + case O_CREAT|O_TRUNC: + shmid = Backend()->iIpcS.shmget(shmkey, SHM_CHUNKSIZE, IPC_CREAT|perms, aerr); + if (shmid == -1) + { + err = aerr; + return err; + } + if (Backend()->iIpcS.shmctl(shmid, IPC_RMID, buf, aerr) == -1) + { + err = aerr; + return err; + } + shmid = Backend()->iIpcS.shmget(shmkey, SHM_CHUNKSIZE, IPC_CREAT|perms, aerr); + if (shmid == -1) + { + err = aerr; + return err; + } + break; + case O_CREAT|O_EXCL: + case O_CREAT|O_EXCL|O_RDWR: + shmid = Backend()->iIpcS.shmget(shmkey, SHM_CHUNKSIZE, IPC_CREAT|IPC_EXCL|perms, aerr); + if (shmid == -1) + { + err = aerr; + return err; + } + break; + case O_CREAT|O_EXCL|O_TRUNC: + case O_CREAT|O_EXCL|O_TRUNC|O_RDWR: + shmid = Backend()->iIpcS.shmget(shmkey, SHM_CHUNKSIZE, IPC_CREAT|IPC_EXCL|perms, aerr); + if (shmid == -1) + { + err = aerr; + return err; + } + if (Backend()->iIpcS.shmctl(shmid, IPC_RMID, buf, aerr) == -1) + { + err = aerr; + return err; + } + shmid = Backend()->iIpcS.shmget(shmkey, SHM_CHUNKSIZE, IPC_CREAT|IPC_EXCL|perms, aerr); + if (shmid == -1) + { + err = aerr; + return err; + } + break; + default: + shmid = Backend()->iIpcS.shmget(shmkey, SHM_CHUNKSIZE, perms, aerr); + if (shmid == -1) + { + err = aerr; + return err; + } + break; + } + ptr = Backend()->iIpcS.shmat(shmid, (void *)NULL, 0, aerr); + if (ptr == (void*)-1) + { + err = aerr; + return err; + } + iPtr = ptr; + iKey = shmkey; + return err; + } + +TInt CSharedMemDesc::ShmRead(TUint8* aPtr,TInt aLength) + { + TInt err = KErrNone; + iSize = Backend()->iIpcS.GetShmSize(iKey, err); + TInt diff = iSize - iPos; + if (aLength >= diff) + aLength = diff; + TPtr8 ptr(aPtr, aLength); + ptr.Copy((TUint8*)(iPtr)+iPos, aLength); + TInt r = ptr.Length(); + iPos += r; + return r; + } + +TInt CSharedMemDesc::DoShmRead (TDes8& aDesc) + { + TUint8* p = (TUint8*) aDesc.Ptr(); + TInt max = aDesc.MaxLength(); + TInt ret = ShmRead(p, max); + p += ret; + aDesc.SetLength(p-aDesc.Ptr()); + return aDesc.Length(); + } + + +// ----------------------------------------------------------------------------- +// CSharedMemDesc::Read +// Reading from a sharedmemory +// ----------------------------------------------------------------------------- +void CSharedMemDesc::Read(TDes8& aDesc, TRequestStatus& aStatus) + { + //return if its an invalid fd + if(iFdAttrib & KInvalidFd) + { + Complete(aStatus, KErrBadHandle); + return; + } + //Acquire the Lock before read and release it later + iLock.Wait(); + Complete(aStatus,DoShmRead(aDesc)); + iLock.Signal(); + } + +TInt CSharedMemDesc::ShmWrite(TUint8* aPtr,TInt aLength) + { + TInt err = KErrNone; + TInt size = Backend()->iIpcS.GetShmSize(iKey, err); + TPtrC8 ptr(aPtr,aLength); + TUint8* bufPtr = const_cast(ptr.Ptr()); + TInt len = ptr.Length(); + TInt r = Min(aLength, len); + Mem::Copy((TUint8*)(iPtr)+iPos, bufPtr, r); + iPos += r; + if (iPos > iExt && iExt >= 0) + iExt = iPos; + if (iExt <= size) + iSize = iExt = size; + else + iSize = iExt; + Backend()->iIpcS.SetShmSize(iKey, iSize, err); + return r; + } + +TInt CSharedMemDesc::DoShmWrite (TDes8& aDesc) + { + TUint8* p = (TUint8*) aDesc.Ptr(); + TInt max = aDesc.Length(); + return ShmWrite(p, max); + } + +// ----------------------------------------------------------------------------- +// CSharedMemDesc::Write +// Writing to sharedmemory +// ----------------------------------------------------------------------------- +void CSharedMemDesc::Write(TDes8& aDesc, TRequestStatus& aStatus) + { + //return if its an invalid fd + if(iFdAttrib & KInvalidFd) + { + Complete(aStatus, KErrBadHandle); + return; + } + //Acquire the Lock before write and release it later + iLock.Wait(); + Complete(aStatus,DoShmWrite(aDesc)); + iLock.Signal(); + } + +// ----------------------------------------------------------------------------- +// CSharedMemDesc::Fcntl +// fcntl Implementation for sharedmemory +// ----------------------------------------------------------------------------- +// +TInt CSharedMemDesc::Fcntl(TUint anArg, TUint aCmd) + { + //return if its an invalid fd + if(iFdAttrib & KInvalidFd) + { + return KErrBadHandle; + } + TInt retVal = KErrNotSupported; + //fcntl supports only F_SETFL and F_GETFL for Non-Blocking I/O + //If aCmd and anArg does not match these, return with Error + switch(aCmd) + { + case F_SETFL: + { + //Set the fcntl Flag + if(anArg == O_NONBLOCK) + { + iFcntlFlag |= anArg ; + } + retVal = 0 ; + break; + } + case F_GETFL: + { + //Return fcntl flag + retVal = iFcntlFlag; + break; + } + case F_GETFD: + { + if(iFdAttrib & KCloseonExec) + { + retVal = 1; + } + break; + } + case F_SETFD: + { + if(anArg == 1) + { + iFdAttrib |= SET_CLOSE_ON_EXEC_FLG; // (1 << 2) ; + retVal = anArg; + } + else if(anArg == 0 ) + { + iFdAttrib &= ~SET_CLOSE_ON_EXEC_FLG; //(1 << 2) ; + retVal = anArg; + } + else + { + retVal = KErrArgument; //return invalid argument + } + break; + } + } + return retVal; + } + +// ----------------------------------------------------------------------------- +// CSharedMemDesc::FStat +// stat Implementation for sharedmemory +// ----------------------------------------------------------------------------- +// +TInt CSharedMemDesc::FStat(struct stat *st) + { + // set mode as directory + TInt err = 0, aerr =0; + TInt shmid = 0; + struct shmid_ds shmDesc; + st->st_mode = S_IFREG|iPerms; + shmid = Backend()->iIpcS.shmget(iKey, SHM_CHUNKSIZE, iPerms, aerr); + Backend()->iIpcS.shmctl(shmid, IPC_STAT, &shmDesc, aerr); + st->st_uid = shmDesc.shm_perm.cuid; + st->st_gid = 0; + st->st_size = Backend()->iIpcS.GetShmSize(iKey, err); + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CSharedMemDesc::FinalClose +// stat Implementation for sharedmemory +// ----------------------------------------------------------------------------- +// +TInt CSharedMemDesc::FinalClose() + { + TInt err = 0; + TInt ret = KErrNone; + ret = Backend()->iIpcS.shmdt(iPtr, err); + iLock.Close(); + return ret; + } + +TInt CSharedMemDesc::Pos() + { + return iPos; + } + +TInt CSharedMemDesc::Ext() + { + return iExt; + } + +//------------------------------------------------------------------------------- +// Function Name : CSharedMemDesc::LSeek() +// Description : Shall seek to specific position of shared memory +//------------------------------------------------------------------------------- +TInt CSharedMemDesc::LSeek (off_t& offset, int whence) + { + //return if its an invalid fd + //This scenario comes when the file is closed, but mmap still exists + if(iFdAttrib & KInvalidFd) + { + return KErrBadHandle; + } + TInt pos=offset; + TInt ext=Ext(); + switch (whence) + { + case SEEK_SET: + break; + case SEEK_CUR: + pos += Pos(); + break; + case SEEK_END: + pos += ext; + break; + default: + return KErrArgument; + } + if (pos < 0) + { + return KErrArgument; + } + iPos = pos; + offset = pos; + return KErrNone; + } + +#endif //SYMBIAN_OE_LIBRT +