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 sl@0: #include sl@0: #include "LPOSIX.H" sl@0: #include sl@0: #include 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=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 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 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"