sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // POSIX systems calls implemented over EPOC32
sl@0: // 
sl@0: //
sl@0: 
sl@0: #include "SYSIF.H"
sl@0: #include <unistd.h>
sl@0: #include <errno.h>
sl@0: #include "LPOSIX.H"
sl@0: #include <utf.h>
sl@0: #include <networking/dnd_err.h>
sl@0: 
sl@0: GLDEF_C TInt GetFullPath(TParse& aParse, const TText16* upath, RFs& aSession, TDes* aFileName)
sl@0: //
sl@0: // Parse a path of the form "[C:][\]AAA\..\.\BBB\xxx" where:
sl@0: // .  indicates the current directory
sl@0: // .. indicates move to the parent directory
sl@0: // An optional "\" at the start of the path indicates the path is not relative to the current path,
sl@0: // and is implied if the drive specifier is present
sl@0: // If aFileName is non-NULL then the final component is a filename and should be copied into 
sl@0: // the aFileName descriptor.
sl@0: //
sl@0: 	{
sl@0: 
sl@0: 	TInt r;
sl@0: 	TBuf<3> drive;
sl@0: 	TFileName nextBit;
sl@0: 	TText16 c=*upath;
sl@0: 
sl@0: 	if (c && upath[1]==KDriveDelimiter) 
sl@0: 		{
sl@0: 		// drive name specified
sl@0: 		if (c==L'?')
sl@0: 			drive.Zero();			// use "?:" to mean scan across drives
sl@0: 		else
sl@0: 			{
sl@0: 			drive.Copy(TPtrC16(upath, 2));
sl@0: 			drive.UpperCase();
sl@0: 			}
sl@0: 		upath+=2;
sl@0: 		drive.Append(TChar(KPathDelimiter));	// enforce absoluteness
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		// no leading drive specifier
sl@0: 		drive.Zero();
sl@0: 		if (c==KPathDelimiter||c==L'/')
sl@0: 			{
sl@0: 			upath+=1;
sl@0: 			drive.Append(TChar(KPathDelimiter));
sl@0: 			}
sl@0: 		}
sl@0: 	r = aSession.Parse(drive, aParse);
sl@0: 
sl@0: 	// upath now looks like a relative pathname, to be added onto
sl@0: 	// aParse a directory at a time. Note that '/' is not allowed in
sl@0: 	// EPOC32 file or directory names, so treat it as an alternative separator
sl@0: 
sl@0: 	c=*upath;
sl@0: 	while (c && (r==KErrNone))
sl@0: 		{
sl@0: 		const TText16* ustart=upath;
sl@0: 		do 
sl@0: 			c=*upath++;
sl@0: 		while (c && c!=KPathDelimiter && c!=L'/');
sl@0: 
sl@0: 		TInt len=(upath-ustart)-1;		// excludes delimiter
sl@0: 		if (len==0)
sl@0: 			continue;
sl@0: 		if (ustart[0]==L'.')
sl@0: 			{
sl@0: 			if (len==1)
sl@0: 				continue;	// directory . ignored
sl@0: 			if (len==2 && ustart[1]==L'.')
sl@0: 				{
sl@0: 				// directory ..
sl@0: 				(void) aParse.PopDir();	// just stick at root dir, no errors
sl@0: 				continue;
sl@0: 				}
sl@0: 			}
sl@0: 		if (len>=KMaxFileName)
sl@0: 			return ENAMETOOLONG;
sl@0: 		if (c==L'\0' && aFileName!=NULL)
sl@0: 			{
sl@0: 			// it's the trailing filename
sl@0: 			aFileName->Copy(TPtrC16(ustart, len));
sl@0: 			break;
sl@0: 			}
sl@0: 		else	
sl@0: 			{
sl@0: 			// it's a component of the accumulating path
sl@0: 			nextBit.Copy(TPtrC16(ustart, len));
sl@0: 			r = aParse.AddDir(nextBit);
sl@0: 			}
sl@0: 		}
sl@0: 	return(r);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: GLDEF_C TInt GetFullFile(TFileName& aName, const TText16* upath, RFs& aSession)
sl@0: // Use GetFullPath to establish the pathname, then add the filename onto the end
sl@0: 	{
sl@0: 	TParse path;
sl@0: 	TInt err = GetFullPath(path,upath,aSession,&aName);
sl@0: 	if (err!=KErrNone)
sl@0: 		return err;
sl@0: 	// Wildcard drive letter for searching across drives
sl@0: 	if (upath[0]==L'?' && upath[1]==L':')
sl@0: 		{
sl@0: 		TFindFile search(aSession);
sl@0: 		err=search.FindByDir(aName,path.Path());
sl@0: 		if (!err)
sl@0: 			{
sl@0: 			aName=search.File();
sl@0: 			return KErrNone;
sl@0: 			}
sl@0: 		}
sl@0: 	err = path.SetNoWild(path.DriveAndPath(),NULL,&aName);
sl@0: 	if (!err)
sl@0: 		aName = path.FullName();
sl@0: 	return err;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // Set errno from an E32STD.H error code or a STDLIB errno value
sl@0: 
sl@0: static const TUint8 EPOCtoERRNO[43] = {
sl@0: 	ENOENT,   // KErrNotFound=(-1);
sl@0: 	  0,      // KErrGeneral=(-2);
sl@0: 	EINTR,    // KErrCancel=(-3);
sl@0: 	ENOMEM,   // KErrNoMemory=(-4);
sl@0: 	ENOSYS,   // KErrNotSupported=(-5);
sl@0: 	EINVAL,   // KErrArgument=(-6);
sl@0: 	  0,      // KErrTotalLossOfPrecision=(-7);
sl@0: 	  0,      // KErrBadHandle=(-8);
sl@0: 	ERANGE,   // KErrOverflow=(-9);
sl@0: 	ERANGE,   // KErrUnderflow=(-10);
sl@0: 	EEXIST,   // KErrAlreadyExists=(-11);
sl@0: 	ENOENT,   // KErrPathNotFound=(-12);
sl@0: 	EPIPE,    // KErrDied=(-13);
sl@0: 	EACCES,   // KErrInUse=(-14);
sl@0: 	EPIPE,    // KErrServerTerminated=(-15);
sl@0: 	EBUSY,    // KErrServerBusy=(-16);
sl@0: 	  0,      // KErrCompletion=(-17);
sl@0: 	  0,      // KErrNotReady=(-18);
sl@0: 	  0,      // KErrUnknown=(-19);
sl@0: 	  0,      // KErrCorrupt=(-20);
sl@0: 	EACCES,   // KErrAccessDenied=(-21);
sl@0: 	EACCES,   // KErrLocked=(-22);
sl@0: 	  0,      // KErrWrite=(-23);
sl@0: 	ENODEV,   // KErrDisMounted=(-24);
sl@0: 	EPIPE,    // KErrEof=(-25);
sl@0: 	ENOSPC,   // KErrDiskFull=(-26);
sl@0: 	  0,      // KErrBadDriver=(-27);
sl@0: 	EINVAL,   // KErrBadName=(-28);
sl@0: 	ECOMM,    // KErrCommsLineFail=(-29);
sl@0: 	ECOMM,    // KErrCommsFrame=(-30);
sl@0: 	ECOMM,    // KErrCommsOverrun=(-31);
sl@0: 	ECOMM,    // KErrCommsParity=(-32);
sl@0:     ETIMEDOUT,    // KErrTimedOut=(-33);
sl@0:     ECONNREFUSED, // KErrCouldNotConnect=(-34);
sl@0: 	  0,      // KErrCouldNotDisconnect=(-35);
sl@0: 	EPIPE,    // KErrDisconnected=(-36);
sl@0: 	  0,      // KErrBadLibraryEntryPoint=(-37);
sl@0: 	  0,      // KErrBadDescriptor=(-38);
sl@0: 	  0,      // KErrAbort=(-39);
sl@0: 	  0,      // KErrTooBig=(-40);
sl@0: 	EDOM,     // KErrDivideByZero=(-41);
sl@0: 	EDOM,     // KErrBadPower=(-42);
sl@0: 	ENOSPC    // KErrDirFull=(-43);
sl@0: 	};
sl@0: 
sl@0: 
sl@0: EXPORT_C int MapError(TInt err, int& anErrno)
sl@0: 	{
sl@0: 	if (err==0)
sl@0: 		return err;	// i.e. return 0 without changing errno
sl@0: 	TInt ret=err;
sl@0: 	if (err<KErrNone && err>=KErrDirFull)
sl@0: 		{
sl@0: 		ret=EPOCtoERRNO[-1-err];
sl@0: 		if (ret==0)
sl@0: 			ret=err;	// no sensible translation
sl@0: 		}
sl@0: 	else if ((err == KErrDndNameNotFound) || (err == KErrDndAddrNotFound))
sl@0: 		// KErrDndNameNotFound Returned when no data found for GetByName
sl@0: 		// KErrDndAddrNotFound Returned when no data found for GetByAddr
sl@0: 		{
sl@0: 		ret=ENOENT;
sl@0: 		}
sl@0: 	anErrno=ret;	// KErr* values are negative, so will be distinct anyway
sl@0: 	return -1;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: // Directory enumeration
sl@0: 
sl@0: NONSHARABLE_STRUCT(__EPOC32_WDIR) : public CBase	// aka "class __EPOC32_WDIR with everything public"
sl@0: 	{
sl@0: public:
sl@0: 	__EPOC32_WDIR(struct _reent* aContext) : iContext(aContext) {}
sl@0: 	~__EPOC32_WDIR();
sl@0: 
sl@0: 	TInt Open();
sl@0: 	TInt Open(const TDesC& aPath);
sl@0: 	TInt Open(const wchar_t *_path);
sl@0: 
sl@0: 	virtual TInt UpdateNarrow();
sl@0: 	struct _reent *iContext;
sl@0: 	HBufC* iPath;
sl@0: 	CDir* iEntries;
sl@0: 	TInt iIndex;		// counting down, 0 means "finished"
sl@0: 	struct wdirent iCurrent;
sl@0: 	TBuf16<KMaxFileName> iCurrentName;
sl@0: 	};
sl@0: 
sl@0: TInt __EPOC32_WDIR::UpdateNarrow()
sl@0: {
sl@0: 	return -1;		//this is not supported.
sl@0: }
sl@0: 
sl@0: 
sl@0: NONSHARABLE_STRUCT(__EPOC32_DIR) : public __EPOC32_WDIR
sl@0: 	{
sl@0: public:
sl@0: 	__EPOC32_DIR(struct _reent* aContext) : __EPOC32_WDIR(aContext) {}
sl@0: 	~__EPOC32_DIR() {}
sl@0: 
sl@0: 	virtual TInt UpdateNarrow();
sl@0: 	struct dirent iCurrentNarrow;
sl@0: 	TBuf8<KMaxFileName> iCurrentNarrowName;
sl@0: 	};
sl@0: 
sl@0: 
sl@0: TInt __EPOC32_DIR::UpdateNarrow()
sl@0: {
sl@0: 	//update the narrow one
sl@0: 	
sl@0: 	TInt ret = CnvUtfConverter::ConvertFromUnicodeToUtf8(iCurrentNarrowName, iCurrentName);
sl@0: 	if (ret >= 0)
sl@0: 		{
sl@0: 		iCurrentNarrow.d_namlen=(short)iCurrentNarrowName.Length();
sl@0: 		iCurrentNarrow.d_name = (char*)iCurrentNarrowName.PtrZ();
sl@0: 		}
sl@0: 	return ret;
sl@0: }
sl@0: 
sl@0: 
sl@0: __EPOC32_WDIR::~__EPOC32_WDIR()
sl@0: 	{
sl@0: 	delete iPath;
sl@0: 	delete iEntries;
sl@0: 	}
sl@0: 
sl@0: TInt __EPOC32_WDIR::Open(const wchar_t *_path)
sl@0: 	{
sl@0: 	MSystemInterface& sysIf=Interface(iContext);
sl@0: 	TParse name;
sl@0: 	TInt err = sysIf.ResolvePath(name,_path,NULL);
sl@0: 	if (!err)
sl@0: 		err = Open(name.DriveAndPath());
sl@0: 	if (err)
sl@0: 		MapError(err,iContext->_errno);
sl@0: 	return err;
sl@0: 	}
sl@0: 
sl@0: TInt __EPOC32_WDIR::Open(const TDesC& aPath)
sl@0: 	{
sl@0: 	delete iPath;
sl@0: 	iPath=aPath.Alloc();		//allocate space for a hbufc and initialise it to the TDesC contents
sl@0: 	return Open();
sl@0: 	}
sl@0: 
sl@0: TInt __EPOC32_WDIR::Open()
sl@0: 	{
sl@0: 	delete iEntries;
sl@0: 	iEntries=0;
sl@0: 	iIndex=-1;
sl@0: 	if (iPath==0)
sl@0: 		return ENOMEM;
sl@0: 	RFs session;
sl@0: 	TInt err=session.Connect();
sl@0: 	if (err)
sl@0: 		return err;
sl@0: 	err=session.GetDir(*iPath,KEntryAttMaskSupported,ESortByName+EDescending,iEntries);
sl@0: 	session.Close();
sl@0: 	if (!err)
sl@0: 		iIndex=iEntries->Count();
sl@0: 	return err;
sl@0: 	}
sl@0: 
sl@0: extern "C" {
sl@0: 
sl@0: /**
sl@0: Resets the position to the beginning of the directory.
sl@0: @param dp directory
sl@0: */
sl@0: EXPORT_C void wrewinddir (WDIR *dp)
sl@0: 	{
sl@0: 	if (dp==0)
sl@0: 		return;
sl@0: 	(void) dp->Open();	// POSIX doesn't allow for rewind failing
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Closes the directory.
sl@0: @param dp directory to close.
sl@0: */
sl@0: EXPORT_C int wclosedir (WDIR *dp)
sl@0: 	{
sl@0: 	delete dp;
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Opens a directory.
sl@0: @return a pointer to the dir object.
sl@0: This object describes the directory 
sl@0: and is used in subsequent operations on the directory
sl@0: If error, returns NULL.
sl@0: @param _path path to the directory to be opened.
sl@0: */
sl@0: EXPORT_C DIR *opendir (const char *_path)
sl@0: 	{
sl@0: 	return _opendir_r(_REENT,_path);
sl@0: 	}
sl@0: 
sl@0: /** A wide-character version of opendir()
sl@0: */
sl@0: EXPORT_C WDIR *wopendir (const wchar_t *_path)
sl@0: 	{
sl@0: 	return _wopendir_r(_REENT,_path);
sl@0: 	}
sl@0: 
sl@0: /** A reentrant version of opendir().
sl@0: */
sl@0: EXPORT_C DIR *_opendir_r (struct _reent *r, const char *_path)
sl@0: 	{
sl@0: 	
sl@0: 	wchar_t _widepath[KMaxFileName+1];
sl@0: 	
sl@0: 	if (mbstowcs(_widepath, _path, KMaxFileName) < 0)
sl@0: 		{
sl@0: 		MapError(EILSEQ,r->_errno);
sl@0: 		return 0;
sl@0: 		}
sl@0: 	//coverity[alloc_fn]
sl@0: 	//coverity[assign]
sl@0: 
sl@0: 	DIR* dp = new __EPOC32_DIR(r);
sl@0: 	if (dp==0)
sl@0: 		{
sl@0: 		r->_errno=ENOMEM;
sl@0: 		return 0;
sl@0: 		}
sl@0: 	
sl@0: 	//coverity[leave_without_push]
sl@0: 
sl@0: 	TInt err = dp->Open(_widepath);
sl@0: 	if (err)
sl@0: 		{
sl@0: 		delete dp;
sl@0: 		return 0;
sl@0: 		}
sl@0: 	return dp;
sl@0: 	}
sl@0: 
sl@0: /** A reentrant version of wopendir().
sl@0: */
sl@0: EXPORT_C WDIR *_wopendir_r (struct _reent *r, const wchar_t *_path)
sl@0: 	{
sl@0: 
sl@0: 	//coverity[alloc_fn]
sl@0: 	//coverity[assign]
sl@0: 
sl@0: 	WDIR* dp = new __EPOC32_WDIR(r);
sl@0: 	if (dp==0)
sl@0: 		{
sl@0: 		r->_errno=ENOMEM;
sl@0: 		return 0;
sl@0: 		}
sl@0: 	//coverity[leave_without_push]
sl@0: 
sl@0: 	TInt err = dp->Open(_path);
sl@0: 	if (err)
sl@0: 		{
sl@0: 		delete dp;
sl@0: 		return 0;
sl@0: 		}
sl@0: 	return dp;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Sets the index position of the directory stream specified by dp 
sl@0: to the position specified by index.
sl@0: */
sl@0: EXPORT_C void wseekdir(WDIR *dp,off_t index)
sl@0: 	{
sl@0: 	dp->iIndex=index;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C off_t wtelldir(const WDIR *dp)
sl@0: 	{
sl@0: 	return dp->iIndex;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C struct wdirent *wreaddir (WDIR *dp)
sl@0: 	{
sl@0: 	if (dp->iIndex<=0)
sl@0: 		return 0;
sl@0: 	struct wdirent *ep=&dp->iCurrent;
sl@0: 	const TEntry& entry=(*dp->iEntries)[--(dp->iIndex)];
sl@0: 	// in practice, these files must have been created as "X:\something", so they
sl@0: 	// can't really be longer than KMaxFileName-3
sl@0: 	dp->iCurrentName.Copy(entry.iName);
sl@0: 	dp->iCurrentName.ZeroTerminate();
sl@0: 	ep->d_namlen=(short)dp->iCurrentName.Length();
sl@0: 	ep->d_name=(wchar_t*)dp->iCurrentName.PtrZ();
sl@0: 	return ep;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Returns  a  pointer  to a dirent structure representing 
sl@0: the next  directory  entry  in  the directory  stream  pointed  to be dir.
sl@0: It returns NULL on reaching the end-of-file or if an error occurred.
sl@0: @return a  pointer  to a dirent structure, or NULL if an error occurs
sl@0: or  end-of-file  is reached.
sl@0: @param dp Points to the directory stream of the directory.
sl@0: */
sl@0: EXPORT_C struct dirent *readdir (DIR *dp)
sl@0: 	{
sl@0: 	return _readdir_r(_REENT, dp);
sl@0: 	}
sl@0: 
sl@0: /** A reentrant version of readdir().
sl@0: */
sl@0: EXPORT_C struct dirent *_readdir_r (struct _reent *r, DIR *dp)
sl@0: 	{
sl@0: 	if (wreaddir(dp))
sl@0: 		{
sl@0: 		if (dp->UpdateNarrow()>=0)
sl@0: 			return &dp->iCurrentNarrow;
sl@0: 		else
sl@0: 			r->_errno = EINVAL;
sl@0: 		}
sl@0: 
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Sets the position (associated with the directory stream that dirp points to) 
sl@0: to the beginning of the directory. 
sl@0: Additionally, it causes the directory stream to refer to the current state of 
sl@0: the corresponding directory.
sl@0: @param dp Points to the directory stream of the directory to rewind.
sl@0: */
sl@0: EXPORT_C void rewinddir (DIR *dp)
sl@0: 	{
sl@0: 	wrewinddir(dp);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: closes the directory stream that dirp refers to. 
sl@0: The memory associated with the directory stream is released. 
sl@0: When this function returns, the value of dirp no longer point to 
sl@0: an accessible object of type DIR
sl@0: @return a value of zero. On failure, it returns -1
sl@0: @param dp Is the directory pointer to close (from opendir()).
sl@0: */
sl@0: EXPORT_C int closedir (DIR *dp)
sl@0: 	{
sl@0: 	return wclosedir(dp);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: sets the position of the next readdir() operation on the directory 
sl@0: stream specified by dp to the position specified by index
sl@0: @param dp Points to the directory stream of the directory
sl@0: @param index
sl@0: */
sl@0: EXPORT_C void seekdir(DIR *dp,off_t index)
sl@0: 	{
sl@0: 	wseekdir(dp,index);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Returns the current location associated with the directory stream dir.
sl@0: @return the current location in the directory stream or -1 if an error occurs. 
sl@0: @param dp Points to the directory stream of the directory
sl@0: */
sl@0: EXPORT_C off_t telldir(const DIR *dp)
sl@0: 	{
sl@0: 	return wtelldir(dp);
sl@0: 	}
sl@0: 
sl@0: } // extern "C"