--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericopenlibs/cstdlib/USTLIB/FDESC.CPP Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,783 @@
+// 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 "FDESC.H"
+#include "LPOSIX.H"
+#include "LTIME.H"
+#include <string.h>
+#include <stdio_r.h>
+#include <fcntl.h> // for struct stat
+#include <sys/errno.h> // for ENOTSOCK
+#include <sys/ioctl.h>
+#include <c32comm.h>
+
+#include "POSIXIF.H" // for details of CPosixRequest::iLink
+
+// Cleanup support
+
+void CFileDescBase::Cleanup(TAny *aPtr)
+ {
+ ((CFileDescBase*)aPtr)->Close();
+ }
+
+void CFileDescBase::PushLC()
+ {
+ CleanupStack::PushL(TCleanupItem(Cleanup,this));
+ }
+
+// Private constructor
+
+inline TPosixRequestQueue::TPosixRequestQueue()
+: TSglQue<CPosixRequest>(_FOFF(CPosixRequest,iLink))
+ {}
+
+CFileDescBase::CFileDescBase() : iReadTimeout(-1)
+ {
+ }
+
+// A CFileDescBase factory function, for "named" file-like objects
+
+//CFileDescBase* CFileDescBase::Open(RFs& aSession, const char* name, int mode, int perms, TInt& err)
+//CFileDescBase* CFileDescBase::Open(RFs& aSession, const wchar_t* name, int mode, int perms, TInt& err)
+CFileDescBase* CFileDescBase::Open(RSessionBase& aSession, const wchar_t* name, int mode, int perms, TInt& err)
+ {
+ CFileDescBase* ret=0;
+
+ 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)
+ {
+ RFs& rfs = static_cast<RFs&>(aSession);
+ TParse path;
+ err=GetFullPath(path,(const TText16*)WIDEP_tmpdir, rfs,NULL);
+ if (err)
+ return 0;
+ CTempFileDesc* tmp= new CTempFileDesc;
+ if (tmp)
+ {
+ err=tmp->Open(rfs,path.DriveAndPath());
+ if (err)
+ {
+ delete tmp;
+ return 0;
+ }
+ }
+ ret=tmp;
+ }
+ 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')))
+ {
+
+ RCommServ& rcs = static_cast<RCommServ&>(aSession);
+ if (!rcs.Handle())
+ {
+ err=rcs.Connect(); //connect to the server
+ if (err)
+ return 0;
+ }
+ CSerialDesc * tmp = new CSerialDesc;
+ if (tmp)
+ {
+ RCommServ& rcs = static_cast<RCommServ&>(aSession);
+ CleanupStack::PushL(tmp);
+ err = tmp->Open(rcs, name, mode, perms);
+ CleanupStack::Pop(tmp);
+ if (err)
+ {
+ delete tmp;
+ return 0;
+ }
+ }
+ ret = tmp;
+ }
+ else
+ {
+ TFullName fullName;
+ RFs& rfs = static_cast<RFs&>(aSession);
+ err=GetFullFile(fullName,(const TText16*)name,rfs);
+ if (err)
+ return 0;
+ CFileDesc* f= new CFileDesc;
+ if (f)
+ {
+ err=f->Open(rfs,fullName,mode,perms);
+ if (err)
+ {
+ delete f;
+ return 0;
+ }
+ }
+ ret=f;
+ }
+ err=(ret==0)? KErrNoMemory:KErrNone;
+ return ret;
+ }
+
+// Useful default implementations for CFileDescBase virtual functions.
+
+TInt CFileDescBase::LSeek (int& offset, int)
+ {
+ // minimal implementation for devices which can't seek
+ offset=0;
+ return KErrNone;
+ }
+
+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(int*,aParam);
+ switch (aCmd)
+ {
+ 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;
+ }
+ CSocketDesc* s= new CSocketDesc;
+ if (s==0)
+ {
+ err=KErrNoMemory;
+ return 0;
+ }
+ err=s->Socket(aSs,family,style,protocol);
+ if (err)
+ {
+ delete s;
+ return 0;
+ }
+ return s;
+ }
+
+// 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::RecvFromCompletion(TInt& /*aLength*/, TInt aStatus)
+ {
+ return aStatus;
+ }
+
+void CFileDescBase::SendTo(TDes8& /*aDesc*/, TSockAddr& /*to*/, int /*flags*/, TRequestStatus& aStatus)
+ {
+ // minimal implementation
+ Complete(aStatus,ENOTSOCK);
+ }
+
+void CFileDescBase::SendToCancel () {}
+
+TInt CFileDescBase::SendToCompletion(TDes8& /*aDesc*/, TInt aStatus)
+ {
+ return aStatus;
+ }
+
+void CFileDescBase::Shutdown(TUint /*aHow*/,TRequestStatus& aStatus)
+ {
+ // minimal implementation
+ Complete(aStatus,ENOTSOCK);
+ }
+
+void CFileDescBase::ShutdownCancel () {}
+
+TInt CFileDescBase::Bind(TSockAddr& /*anAddr*/)
+ {
+ return ENOTSOCK;
+ }
+
+TInt CFileDescBase::Listen(TUint /*qSize*/)
+ {
+ return ENOTSOCK;
+ }
+
+void CFileDescBase::Accept(CSocketDesc*& /*aNewSocket*/, TRequestStatus& aStatus, RSocketServ& /*aSs*/)
+ {
+ // minimal implementation
+ Complete(aStatus,ENOTSOCK);
+ }
+
+void CFileDescBase::AcceptCancel () {}
+
+void CFileDescBase::Connect(TSockAddr& /*anAddr*/,TRequestStatus& aStatus)
+ {
+ // minimal implementation
+ Complete(aStatus,ENOTSOCK);
+ }
+
+void CFileDescBase::ConnectCancel () {}
+
+TInt CFileDescBase::SockName(int /*anEnd*/, TSockAddr& /*anAddr*/)
+ {
+ return ENOTSOCK;
+ }
+
+TInt CFileDescBase::GetSockOpt(TUint /*anOptionName*/,TUint /*anOptionLevel*/,TDes8& /*anOption*/)
+ {
+ return ENOTSOCK;
+ }
+
+TInt CFileDescBase::SetSockOpt(TUint /*anOptionName*/,TUint /*anOptionLevel*/,TDesC8& /*anOption*/)
+ {
+ return ENOTSOCK;
+ }
+
+// Queue handling
+
+void CFileDescBase::AddLast(CPosixRequest& aRequest, IOQueues aQueue)
+ {
+ TPosixRequestQueue& queue = iQueues[aQueue];
+ queue.AddLast(aRequest);
+ if (queue.IsFirst(&aRequest))
+ aRequest.StartAsynch(); // queue was empty, so start straight away
+ }
+
+void CFileDescBase::Remove(CPosixRequest& aRequest, IOQueues aQueue)
+ {
+ TPosixRequestQueue& queue = iQueues[aQueue];
+ TBool wasFirst = queue.IsFirst(&aRequest);
+ queue.Remove(aRequest);
+ if (wasFirst)
+ {
+ if (!queue.IsEmpty())
+ queue.First()->StartAsynch(); // start the next outstanding request
+ }
+ }
+
+
+// Generic (non-virtual) handling for Close
+
+TInt CFileDescBase::Close()
+ {
+ TInt err=KErrNone;
+ if (--iDupCount < 0)
+ {
+ err=FinalClose();
+ delete this;
+ }
+ return err;
+ }
+
+TInt CFileDescBase::FinalClose()
+ {
+ return KErrNone;
+ }
+
+
+// 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;
+ fMode |= (aMode & O_EXCL) ? EFileShareExclusive : EFileShareAny;
+ }
+ else
+ {
+ fMode = EFileRead;
+ fMode |= (aMode & O_EXCL) ? EFileShareExclusive : EFileShareReadersOnly;
+ }
+
+ fMode |= (aMode & O_TEXT) ? EFileStreamText : EFileStream;
+
+ return aMode & (O_CREAT|O_TRUNC|O_APPEND|O_EXCL);
+ }
+
+CFileDesc::CFileDesc()
+ :CFileDescBase(), iSize(EBufferSize), iExt(-1)
+ {}
+
+CFileDesc::~CFileDesc()
+ {
+ iFile.Close();
+ delete [] iBuffer;
+ }
+
+TInt CFileDesc::FinalClose()
+ {
+ return DoSync();
+ }
+
+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);
+ switch (mapped)
+ {
+ case O_CREAT|O_EXCL:
+ err = iFile.Create(aSession, aName, fMode);
+ break;
+ case O_CREAT|O_TRUNC:
+ err = iFile.Replace(aSession, aName, fMode);
+ break;
+ case O_TRUNC:
+ err = iFile.Open(aSession, aName, fMode);
+ if (err == KErrPathNotFound)
+ {
+ // missing directories etc, so fail directly
+ }
+ else
+ {
+ iFile.Close();
+ err = iFile.Replace(aSession, aName, fMode);
+ }
+ 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 == KErrNone && (mapped & O_APPEND))
+ {
+ iPos = Ext();
+ if (iPos < 0)
+ err = iPos;
+ }
+ break;
+ }
+ if ((mode & O_BUFFERED) == 0)
+ iSize = 0;
+ return err;
+ }
+
+TInt CFileDesc::LSeek (int& offset, int whence)
+ {
+
+ TInt pos=offset;
+ TInt ext=Ext();
+ if (ext < 0)
+ return ext;
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ pos += Pos();
+ break;
+ case SEEK_END:
+ pos += ext;
+ break;
+ default:
+ return KErrArgument;
+ }
+ TInt ret = KErrNone;
+ if (pos < 0)
+ {
+ pos = 0;
+ ret = KErrEof;
+ }
+ else if (pos > ext)
+ {
+ pos = ext;
+ ret = KErrEof;
+ }
+
+ switch (iState)
+ {
+ case EAlloc:
+ iPos = pos;
+ break;
+ case EReading:
+ {
+ TInt 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)
+ iPos = pos;
+ }
+ break;
+ }
+ offset = pos;
+ return ret;
+ }
+
+void CFileDesc::MapStat(struct stat& st, const TTime& aModTime, TUint& aAttr)
+ {
+ st.st_mode = (aAttr&KEntryAttDir) ? S_IFDIR:S_IFREG;
+ if ((aAttr&KEntryAttReadOnly)==0)
+ st.st_mode |= S_IWUSR;
+ st.st_nlink = 1;
+ st.st_mtime = as_time_t(aModTime);
+ st.st_blksize=512;
+ }
+
+TInt CFileDesc::FStat (struct stat* st)
+ {
+ TInt err;
+ TUint att;
+ TTime modtime;
+
+ err = iFile.Att(att);
+ if (!err)
+ {
+ err = iFile.Modified(modtime);
+ if (!err)
+ {
+ err=Ext();
+ if (err >= 0)
+ {
+ st->st_size = err;
+ st->st_dev = st->st_rdev = iDrive;
+ MapStat(*st, modtime, att);
+ return 0;
+ }
+ }
+ }
+ return err;
+ }
+
+TInt CFileDesc::Alloc()
+ {
+ if (iSize)
+ {
+ 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);
+ TInt r = iFile.Write(iPos,ptr);
+ if (r == KErrNone)
+ {
+ 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)
+ {
+ TInt ret = (iState == EAlloc) ? Alloc() : 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 KErrNone;
+ }
+
+void CFileDesc::Read (TDes8& aDesc, TRequestStatus& aStatus)
+ {
+ Complete(aStatus,DoRead(aDesc));
+ }
+
+TInt CFileDesc::DoWrite (TDes8& aDesc)
+ {
+ if (iState != EWriting)
+ {
+ if (iState == EAlloc)
+ {
+ TInt ret = Alloc();
+ if (ret != KErrNone)
+ return ret;
+ }
+ else
+ 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 KErrNone;
+ TInt r=Flush();
+ if (r < 0)
+ return r;
+ if (max >= iSize)
+ return FileWrite(p, max);
+ iPtr = Mem::Copy(iPtr, p, max);
+ return KErrNone;
+ }
+
+void CFileDesc::Write(TDes8& aDesc, TRequestStatus& aStatus)
+ {
+ Complete(aStatus,DoWrite(aDesc));
+ }
+
+TInt CFileDesc::DoSync()
+ {
+ if (iState == EWriting)
+ {
+ TInt ret = Flush();
+ if (ret < 0)
+ return ret;
+ }
+ return iFile.Flush();
+ }
+
+void CFileDesc::Sync(TRequestStatus& aStatus)
+ {
+ Complete(aStatus,DoSync());
+ }
+
+TInt CFileDesc::Pos()
+ {
+ TInt pos = iPos;
+ if (iState == EReading)
+ pos -= (iEnd - iPtr);
+ else if (iState == EWriting)
+ pos += (iPtr - iBuffer);
+ return pos;
+ }
+
+TInt CFileDesc::Ext()
+ {
+ if (iExt < 0)
+ {
+ TInt r = iFile.Size(iExt);
+ if (r < 0)
+ return r;
+ }
+ return Max(iExt, Pos());
+ }
+
+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
+ TInt curoff = Pos();
+ TInt size = Ext();
+ if (size < 0)
+ ret = size;
+ int *param=REINTERPRET_CAST(int*,aParam);
+ switch (aCmd)
+ {
+ 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;
+ }
+
+// Extra support for temporary files
+
+TInt CTempFileDesc::Open(RFs& aSession, const TDesC& aPath)
+ {
+ iSession=aSession;
+ iDrive=(TInt16)TDriveUnit(aPath);
+ TInt err=iFile.Temp(aSession, aPath, iName, EFileShareAny);
+ return err;
+ }
+
+TInt CTempFileDesc::FinalClose()
+ {
+ iFile.Close();
+ TInt err=iSession.Delete(iName);
+ return err;
+ }