

///////////////////////////////////////////////////////////////////
/*
 *              Copyright (C) 2005, BroadOn Communications Corp.
 *
 * These coded instructions, statements, and computer programs contain
 * unpublished  proprietary information of BroadOn Communications Corp.,
 * and  are protected by Federal copyright law. They may not be disclosed
 * to  third  parties or copied or duplicated in any form, in whole or in
 * part, without the prior written consent of BroadOn Communications Corp.
 *
 */

#include "stdafx.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "utils.h"


#ifdef WIN32
#include <winsock2.h>
#include <io.h>
#include "include\fs.h"
#include "include\sc\mediafs.h"
#include "ncmedia.h"
#else /* !WIN32 */
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/time.h>
#endif /* !WIN32 */

/* 
  To make prototype of API same as NC, 
  choose global variable for socket fd.
 */
int ncproxyFd = -1;    
HANDLE hNcproxyFdMutex=NULL;


/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
    Function: syncMediaFs

    Description:
        Keep send SYNC command until get SYNC reply.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int
syncMediaFs(int fd)
{
    struct timeval tm;
    fd_set rfd;
    USBMediaFsRequest req;
    USBMediaFsReply reply;
    int retryTime=20;
	
    req.magic = NC_MEDIA_REQ_MAGIC;
    req.cmd = NC_MEDIA_CMD_SYNC;
    req.dataLen = req.paramLen = 0;

    tm.tv_sec = 5;
    tm.tv_usec = 0;
    
    while (retryTime-->0) {
        ATLTRACE(_T("Send SYNC command ... "));
        hostSend(fd, &req, sizeof(req));

        FD_ZERO(&rfd);
        FD_SET(fd, &rfd);
        if (select(fd+1, &rfd, NULL, NULL, NULL) <= 0) {//&tm
            ATLTRACE(_T("Read reply timeout\n"));
            continue;
        }

        hostRecv(fd, &reply, sizeof(reply));
        
        if ((reply.magic == NC_MEDIA_REPLY_MAGIC) && 
            (reply.cmd == NC_MEDIA_CMD_SYNC) && (reply.retCode >= 0)) {
           ATLTRACE(_T("SYNC reply done\n"));
   	    return 0;
        } else {
            ATLTRACE(_T("Rcv magic=0x%x cmd = %d ret = %d\n"), 
                    reply.magic, reply.cmd, reply.retCode);
	    // Sleep(10);
        }
    }
    ATLTRACE(_T("SYNC reply failure\n"));
    return -1;
}



bool _readSharedMem(int * fd)
{
	HANDLE hMem; // 文件映像对象
	hMem =::CreateFileMapping( 
				(HANDLE)(-1), 
				NULL, 
				PAGE_READWRITE, 
				0, 
				sizeof(ncproxyFd), 
				__T("mappedmemmoryforNcproxyFd")); 
	if ( hMem== 0 ) // 创建文件映像对象失败
	{ 
	   MessageBox(NULL, "Cannot Create FileMap for SubSystem1 ","Error", MB_OK);
	}

	if (::GetLastError() == ERROR_ALREADY_EXISTS) // 对象已经存在
	{ 
		  MessageBox(NULL, "FileMap Already Exists", "Error", MB_OK);
		   int *pInfo = (int *)::MapViewOfFile( hMem, FILE_MAP_WRITE, 0,0,0);
			if ( pInfo == NULL)
			{ 
			MessageBox(NULL, "Cannot Create View of File Mapping", "Error", MB_OK);
			::CloseHandle( hMem);
			return false;
			}
			*fd=*pInfo;
			TCHAR szTemp[100];
			 wsprintf(szTemp,"readSharedMem *pInfo=%d",*pInfo);
			 MessageBox(NULL, szTemp, "Error", MB_OK);
			return true;
	}
	
	return false;
		      
}

bool _WriteSharedMem(int fd)
{
	HANDLE hMem; // 文件映像对象
			hMem =::CreateFileMapping( 
						(HANDLE)(-1), 
						NULL, 
						PAGE_READWRITE, 
						0, 
						sizeof(ncproxyFd), 
						__T("mappedmemmoryforNcproxyFd")); 
			if ( hMem== 0 ) // 创建文件映像对象失败
			{ 
			   MessageBox(NULL, "Cannot Create FileMap for SubSystem1 ","Error", MB_OK);
			}

			if (GetLastError() == ERROR_ALREADY_EXISTS) // 对象已经存在
			{ 
			  MessageBox(NULL, "FileMap Already Exists", "Error", MB_OK);
			}

		       int *pInfo = (int *)::MapViewOfFile( hMem, FILE_MAP_WRITE, 0,0,0);
			if ( pInfo == NULL)
			{ 
			MessageBox(NULL, "Cannot Create View of File Mapping", "Error", MB_OK);
			::CloseHandle( hMem);
			return false;
			}
			*pInfo=fd;
						TCHAR szTemp[100];
			 wsprintf(szTemp,"writeSharedMem *pInfo=%d",*pInfo);
			 MessageBox(NULL, szTemp, "Error", MB_OK);
			 return true;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
    Function: mediaFsOpen

    Description:
        Open media socket and sync PC and NC
 * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int
mediaFsOpen(char *server, int port)
{
    struct sockaddr_in addr;
    int addrLen=sizeof(addr);
#ifdef WIN32
    WSADATA wsd;
    int rv,err;

    if ((rv = WSAStartup(MAKEWORD(2,2), &wsd)) != 0) 
	{
        ATLTRACE(_T("WSAStartup() failed: %d\n"), rv);
        return -1;
    }
#endif
    if(hNcproxyFdMutex==NULL)
    	{
    	    hNcproxyFdMutex=::OpenMutex(
										MUTEX_ALL_ACCESS,
										FALSE,
										_T("NcproxyFdMutex")
										);

			if(hNcproxyFdMutex==NULL)
	    		{
	    			if(::GetLastError()==ERROR_FILE_NOT_FOUND)
	    	   			{
						hNcproxyFdMutex=::CreateMutex( 
							NULL,                       // default security attributes
							FALSE,                      // initially not owned
							_T("NcproxyFdMutex"));                      // NcproxyFdMutex

							if (hNcproxyFdMutex == NULL) 
							{
								ATLTRACE("CreateMutex error: %d\n", ::GetLastError());
								return -1;
							}
							//MessageBox(NULL, " Create hNcproxyFdMutex !!!!!!!!!!!1 ","Error", MB_OK);
	    	   			}
	    		}
	    
    	}

	DWORD dwWaitResult; 

    // Request ownership of mutex.
 
    dwWaitResult = ::WaitForSingleObject( 
        hNcproxyFdMutex,   // handle to mutex
        5000L);   // five-second time-out interval
		//default is 5000l
 
   switch (dwWaitResult) 
    {
        // The thread got mutex ownership.
        case WAIT_OBJECT_0: 
            __try { 
			//try to get ncproxyFd from the shared memory. 
			
			 //  err=_readSharedMem(&ncproxyFd);
			   if(ncproxyFd==-1)
				{
						int tempFd=-1;
				reconnect:
					    tempFd = (int) socket(AF_INET, SOCK_STREAM, 0); 
					    if (tempFd <= 0) {
					        ATLTRACE(_T("Cannot open AF_INET socket to ecp server\n"));
					        return -1;
					    }

					    memset(&addr, 0, sizeof(addr));
					    addr.sin_family = AF_INET;
					    addr.sin_addr.s_addr = inet_addr(server);
					    addr.sin_port = htons(port);

					    if (connect(tempFd, (struct sockaddr *)&addr, addrLen) < 0) {
					        //mediaFsClose_old();
					          shutdown(tempFd, SD_BOTH);
#ifdef WIN32
						closesocket(tempFd);
#else
					        close(tempFd);
#endif
					        ATLTRACE(_T("Cannot connect to NC proxy program\n"));
					        return -2;
					    }

                                       DWORD processID=::GetCurrentProcessId();
					     WSAPROTOCOL_INFO myInfo;
					   int bytesSent,bytesRecv;
					    //send processID to server;
					    bytesSent = send( tempFd, (const char*)&processID, sizeof(DWORD), 0 );
					    bytesRecv = recv( tempFd, (char*)&myInfo, sizeof(WSAPROTOCOL_INFO), 0 );

						shutdown(tempFd, SD_BOTH);
#ifdef WIN32
						closesocket(tempFd);
#else
					        close(tempFd);
#endif

						ncproxyFd=(int)WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,&myInfo,0, WSA_FLAG_OVERLAPPED);
						  if (ncproxyFd <= 0) {
					        ATLTRACE(_T("Cannot open AF_INET socket to NCProxy\n"));
					        return -1;
					    }
				/*
					   if (syncMediaFs(ncproxyFd)) {
					        shutdown(ncproxyFd, SD_BOTH);
#ifdef WIN32
						closesocket(ncproxyFd);
#else
					        close(ncproxyFd);
#endif
					        goto reconnect;
					    }
				*/
					//   err=_WriteSharedMem(ncproxyFd);
			                
				}
            } 

            __finally { 
                // Release ownership of the mutex object.
                if (! ::ReleaseMutex(hNcproxyFdMutex)) 
                { 
                    // Deal with error.
                } 

                break; 
            } 

        // Cannot get mutex ownership due to time-out.
        case WAIT_TIMEOUT: 
            return -1; 

        // Got ownership of the abandoned mutex object.
        case WAIT_ABANDONED: 
            return -1; 
    }

    return ncproxyFd;
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
    Function: mediaFsClose

    Description:
        Close mediaFs
 * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int
mediaFsClose_old()
{
    char buf[8];
    int rd;
    struct timeval tm;
    fd_set rfd;
    shutdown(ncproxyFd, SD_SEND);
    tm.tv_sec = 1;
    tm.tv_usec = 0;

    while (1) {
        FD_ZERO(&rfd);
        FD_SET(ncproxyFd, &rfd);
        if (select(ncproxyFd+1, &rfd, NULL, NULL, &tm) <= 0) {
             ATLTRACE(_T("Waiting close timeout\n"));
            continue;
        }

        rd = recv(ncproxyFd, buf, 8, 0);
        if (rd <= 0) break;
    }
#ifdef WIN32
    closesocket(ncproxyFd);
#else 
    close(ncproxyFd);
#endif
    ncproxyFd = -1;
   // _WriteSharedMem(ncproxyFd);
    ::CloseHandle(hNcproxyFdMutex);
	hNcproxyFdMutex=NULL;
    return 0;
}



int mediaFsClose()
{
DWORD dwWaitResult; 

    // Request ownership of mutex.
 int err;
    dwWaitResult = ::WaitForSingleObject( 
        hNcproxyFdMutex,   // handle to mutex
        5000L);   // five-second time-out interval
 
    switch (dwWaitResult) 
    {
        // The thread got mutex ownership.
        case WAIT_OBJECT_0: 
            __try { 
#ifdef WIN32
              err=0;
              mediaFsClostSocket();
#else
		err= mediaFsClose_old();
#endif 
			} 

            __finally { 
                // Release ownership of the mutex object.
                if (! ReleaseMutex(hNcproxyFdMutex)) 
                { 
                    // Deal with error.
                } 

                break; 
            } 

        // Cannot get mutex ownership due to time-out.
        case WAIT_TIMEOUT: 
            return -2; 

        // Got ownership of the abandoned mutex object.
        case WAIT_ABANDONED: 
            return -1; 
    }
	return err;
}


bool 
mediaFsOpened()
{
	if(ncproxyFd!=-1)
		return true;
	return FALSE;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
    Function: mediaFsTransactions

    Description:
        MediaFs request and reply routines 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ISFSError
mediaFsTransactions_old(
    int cmd, 
    void *param,
    int  paramLen,
    void *dataIn,
    int  dataInLen,
    void *dataOut,
    int dataOutLen)
{
    int ack, pos, len;
    unsigned char *d;
    USBMediaFsRequest req;
    USBMediaFsReply reply;

    req.magic = NC_MEDIA_REQ_MAGIC;
    req.cmd = cmd;
    req.dataLen = dataInLen;
    req.paramLen = paramLen;

    hostRecv(ncproxyFd, &reply, sizeof(reply));
    if (reply.magic != NC_MEDIA_REPLY_MAGIC ||
        reply.retCode != NC_MEDIA_READ_READY) {
        ATLTRACE(_T("recv in wrong state magic = 0x%x retCode=0x%x\n"),
                       reply.magic, reply.retCode);
        return ERROR_USB_LOST_SYNC;
    } 
    hostSend(ncproxyFd, &req, sizeof(req));

    hostRecv(ncproxyFd, &reply, sizeof(reply));
    if (reply.magic != NC_MEDIA_REPLY_MAGIC) {
        ATLTRACE(_T("wrong magic number 0x%x\n"), reply.magic);
        return ERROR_USB_LOST_SYNC;
    }

    if (paramLen > 0) {
        if (reply.retCode == NC_MEDIA_READ_READY) {
            hostSend(ncproxyFd, param, paramLen);
        } else {
            ATLTRACE(_T("sync lost when sending parameter\n"));
            return ERROR_USB_LOST_SYNC;
        }
        hostRecv(ncproxyFd, &reply, sizeof(reply));
    }

    if (dataInLen > 0) {
        if (reply.retCode == NC_MEDIA_READ_READY) {
            d = (unsigned char *) dataIn;
            for (pos=ack=0; pos < dataInLen; ) {
                len = dataInLen -pos;
                if (len >USB_BUF_SIZE) len = USB_BUF_SIZE;

                hostSend(ncproxyFd, d+pos, len);
                pos += len;
                if (ack == 1) {
                    ack = 0;
                    if (pos < dataInLen) hostRecv(ncproxyFd, &reply, sizeof(reply));
                } else ack++;
            }
            hostRecv(ncproxyFd, &reply, sizeof(reply));
        } else {
            ATLTRACE(_T("sync lost when sending data\n"));
            return ERROR_USB_LOST_SYNC;
        }
    }

    /* deal with NC reply */
    if ((reply.magic != NC_MEDIA_REPLY_MAGIC)  || (reply.cmd != cmd)) {
        ATLTRACE(_T("wrong reply cmd = %d magic=0x%x\n"), reply.cmd, reply.magic);
        return ERROR_USB_LOST_SYNC;
    }

    if (reply.retCode >= 0 && dataOut) {
        if (dataOutLen < reply.dataLen) {
            ATLTRACE(_T("given buffer is too small\n"));
            return ERROR_USB_LOST_SYNC; 
        } else {
            d = (unsigned char *) dataOut;
            for (pos = 0; pos < dataOutLen; pos+=USB_BUF_SIZE) {
                len = dataOutLen - pos;
                if (len > USB_BUF_SIZE) len = USB_BUF_SIZE;
                hostRecv(ncproxyFd, d+pos, len);
				}

            if (reply.cmd == NC_MEDIA_CMD_READ) {
                hostRecv(ncproxyFd, &reply, sizeof(reply));
                if ((reply.magic != NC_MEDIA_REPLY_MAGIC)  || (reply.cmd != cmd)) {
                    ATLTRACE(_T("wrong rd reply cmd = %d magic=0x%x\n"), reply.cmd, reply.magic);
                    return ERROR_USB_LOST_SYNC;
                }
               
            }
        }
    }

    return reply.retCode;
}


ISFSError  mediaFsTransactions(
    int cmd, 
    void *param,
    int  paramLen,
    void *dataIn,
    int  dataInLen,
    void *dataOut,
    int dataOutLen)
{
DWORD dwWaitResult; 

    // Request ownership of mutex.
 ISFSError err;
    dwWaitResult = ::WaitForSingleObject( 
        hNcproxyFdMutex,   // handle to mutex
        5000L);   // five-second time-out interval
 
    switch (dwWaitResult) 
    {
        // The thread got mutex ownership.
        case WAIT_OBJECT_0: 
            __try { 
                err= mediaFsTransactions_old( cmd, param,  paramLen,dataIn,  dataInLen, dataOut,  dataOutLen);
            } 

            __finally { 
                // Release ownership of the mutex object.
                if (! ReleaseMutex(hNcproxyFdMutex)) 
                { 
                    // Deal with error.
                } 

                break; 
            } 

        // Cannot get mutex ownership due to time-out.
        case WAIT_TIMEOUT: 
            return -2; 

        // Got ownership of the abandoned mutex object.
        case WAIT_ABANDONED: 
            return -1; 
    }
	return err;
}

void mediaFsClostSocket()
{
	#ifdef WIN32
    closesocket(ncproxyFd);
#else 
    close(ncproxyFd);
#endif
    ncproxyFd = -1;
}

ISFSError 
mediaFsVersion(u8 *ver, int len)
{
    return mediaFsTransactions(NC_MEDIA_CMD_VERSION, NULL, 0, NULL, 0, ver, len);    
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
    Function below should be same as NC fs API
 * * * * * * * * * * * * * * * * * * * * * * * * * * * */

ISFSError 
ISFS_Format(void)
{
    return mediaFsTransactions(ISFS_FORMAT, NULL, 0, NULL, 0, NULL, 0);    
}

ISFSError 
ISFS_GetStats(ISFSStats *stats)
{
    return mediaFsTransactions(ISFS_STATS, NULL, 0, NULL, 0, stats, sizeof(ISFSStats));
}

ISFSError 
ISFS_CreateDir(const u8 *dname, u32 dirAttr, u32 ownerAcc,
                        u32 groupAcc, u32 othersAcc)
{
    int len = strlen((char*)dname) + 1;
    ISFSPathAttrArgs attr;

    if (len > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), dname, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }

    attr.ownerId = attr.groupId = 0;
    memcpy(attr.path, dname, len);
    
    attr.ownerAccess = (u8) ownerAcc;
    attr.groupAccess = (u8) groupAcc;
    attr.othersAccess = (u8) othersAcc;
    attr.attr = (u8) dirAttr;
    
    return mediaFsTransactions(ISFS_DCREATE, &attr, sizeof(attr), NULL, 0, NULL, 0);
}

ISFSError 
ISFS_ReadDir(const u8 *dname, u8 *nameList, u32 *num)
{
    int len = strlen((char*)dname) + 1, rv;
    MediaFsReadDirParam rd;

    if (len > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), dname, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }

    rd.num = *num;
    rd.addr = (u32) nameList;
    memcpy(rd.path, dname, len);

    /* XXXX namelist size is unknown, usb USB_BUF_SIZE for maximum */
    rv = mediaFsTransactions(ISFS_DREAD, &rd, sizeof(rd), NULL, 0, nameList, USB_BUF_SIZE);
    if (rv >= 0) *num = rv;
   
    return (rv >= 0) ? ISFS_ERROR_OK : rv;
} 

ISFSError 
ISFS_SetAttr(const u8 *name, IOSUid ownerId, IOSGid groupId,
             u32 attr, u32 ownerAcc, u32 groupAcc, u32 othersAcc)
{
    int len = strlen((char*)name) + 1;
    ISFSPathAttrArgs myattr;

    if (len > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), name, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }

    myattr.ownerId = ownerId;
    myattr.groupId = groupId;
    memcpy(myattr.path, name, len);
    myattr.ownerAccess = (u8) ownerAcc;
    myattr.groupAccess = (u8) groupAcc;
    myattr.othersAccess = (u8) othersAcc;
    myattr.attr = (u8) attr;
    
    return mediaFsTransactions(ISFS_SETATTR, &myattr, sizeof(myattr), NULL, 0, NULL, 0);
}

ISFSError 
ISFS_GetAttr(const u8 *name, IOSUid *ownerId, IOSGid *groupId,
    u32 *attr, u32 *ownerAcc, u32 *groupAcc, u32 *othersAcc)
{
    int len = strlen((char*)name) + 1;
    ISFSError rv;
    ISFSPathAttrArgs myattr;

    if (len > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), name, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }

    rv = mediaFsTransactions(ISFS_GETATTR, (u8*) name, len, NULL, 0, &myattr, sizeof(myattr));
    if (rv >= 0) {
		if(ownerId!=NULL)
        *ownerId = myattr.ownerId;
		if(groupId!=NULL)
        *groupId = myattr.groupId;
		if(attr!=NULL)
        *attr = myattr.attr;
		if(ownerAcc!=NULL)
        *ownerAcc = myattr.ownerAccess;
		if(groupAcc!=NULL)
        *groupAcc = myattr.groupAccess;
		if(othersAcc!=NULL)
        *othersAcc = myattr.othersAccess;
    }

    return rv;
}

ISFSError 
ISFS_Delete(const u8 *name) 
{
    int len = strlen((char*)name) + 1;

    if (len > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), name, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }

    return mediaFsTransactions(ISFS_DEL, (u8 *) name, len, NULL, 0, NULL, 0);
}

ISFSError 
ISFS_Rename(const u8 *oldName, const u8 *newName)
{
    int len1 = strlen((char*)oldName) + 1;
    int len2 = strlen((char*)newName) + 1;
    ISFSPathsArgs p;

    if (len1 > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), oldName, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }

    if (len2 > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), newName, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }

    memcpy(p.path1, oldName, len1);
    memcpy(p.path2, newName, len2);

    return mediaFsTransactions(ISFS_RENAME, &p, sizeof(p), NULL, 0, NULL, 0);
}

ISFSError 
ISFS_CreateFile(const u8 *fname, u32 fileAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc) 
{
    int len = strlen((char*)fname) + 1;
    ISFSPathAttrArgs attr;

    if (len > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), fname, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }

    attr.ownerId = 0;
    attr.groupId = 0;
    memcpy(attr.path, fname, len);
    attr.ownerAccess = (u8) ownerAcc;
    attr.groupAccess = (u8) groupAcc;
    attr.othersAccess = (u8) othersAcc;
    attr.attr = (u8) fileAttr;
    
    return mediaFsTransactions(ISFS_FCREATE, &attr, sizeof(attr), NULL, 0, NULL, 0);
}

ISFSError 
ISFS_SetFileVersionControl(const u8 *fname, u32 enable)
{
    MediaFsParam p;
    int len = strlen((char*)fname) + 1;
    
    if (len > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), fname, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }
   
    p.arg = enable;
    memcpy(p.path, fname, len);
 
    return mediaFsTransactions(ISFS_FSETVCTRL, &p, sizeof(p), NULL, 0, NULL, 0);
}

IOSFd 
ISFS_Open(const u8 *fname, u32 access)
{
    int len = strlen((char*)fname) + 1;
    MediaFsParam p;
    
    if (len > ISFS_PATH_MAXLEN) {
        ATLTRACE(_T("%s is too long (>%d bytes)\n"), fname, ISFS_PATH_MAXLEN);
        return ISFS_ERROR_INVALID;
    }
     
    p.arg = access;
    memcpy(p.path, fname, len);
 
    return mediaFsTransactions(NC_MEDIA_CMD_OPEN, &p, sizeof(p), NULL, 0, NULL, 0);
}

ISFSError 
ISFS_GetFileStats(IOSFd fd, ISFSFileStats *stats)
{
    MediaFsOpsParam p; 

    p.fd = fd;
    
    return mediaFsTransactions(ISFS_FSTATS , 
                &p, sizeof(p), NULL, 0, stats, sizeof(ISFSFileStats));
    
}

ISFSError 
ISFS_Seek(IOSFd fd, s32 offset, u32 whence)
{
    MediaFsOpsParam p; 

    p.fd = fd;
    p.param0 = offset;
    p.param1 = whence;

    return mediaFsTransactions(NC_MEDIA_CMD_SEEK, &p, sizeof(p), NULL, 0, NULL, 0);
}
                                                                                
ISFSError 
ISFS_Read(IOSFd fd, u8 *buf, u32 size)
{
    MediaFsOpsParam p; 

    p.fd = fd;
    p.param0 = (u32) buf;
    p.param1 = size;

    return mediaFsTransactions(NC_MEDIA_CMD_READ, &p, sizeof(p), NULL, 0, buf, size);
}
                                                                                
ISFSError 
ISFS_Write(IOSFd fd, const u8 *buf, u32 size)
{
    MediaFsOpsParam p; 

    p.fd = fd;
    p.param0 = (u32) buf;
    p.param1 = size;

    return mediaFsTransactions(NC_MEDIA_CMD_WRITE, &p, sizeof(p), (u8 *) buf, size, NULL, 0);
}
                                                                                
ISFSError 
ISFS_Close(IOSFd fd)
{
    MediaFsOpsParam p; 

    p.fd = fd;

    return mediaFsTransactions(NC_MEDIA_CMD_CLOSE, &p, sizeof(p), NULL, 0, NULL, 0);
}

BOOL
ISFS_EOF(IOSFd fd)
{
 ISFSError err;
 ISFSFileStats stats;
 err=ISFS_GetFileStats(fd, &stats);
 if(err<0)
 	{
 	ATLTRACE(_T("Error: ISFS_EOF read file state failed!\r\n"));
 	return FALSE;
 	}
 if(stats.size==stats.offset)return TRUE;
 else return FALSE;
}

int 
ISFS_GetSize(IOSFd fd)
{
ISFSError err;
 ISFSFileStats stats;
 err=ISFS_GetFileStats(fd, &stats);
 if(err<0)
 	{
 	ATLTRACE(_T("Error: ISFS_EOF read file state failed!\r\n"));
 	return err;
 	}
 return stats.size;
}



int 
ISFS_GetPosition(IOSFd fd)
{
ISFSError err;
 ISFSFileStats stats;
 err=ISFS_GetFileStats(fd, &stats);
 if(err<0)
 	{
 	ATLTRACE(_T("Error: ISFS_EOF read file state failed!\r\n"));
 	return err;
 	}
 return stats.offset;
}


//////////////////////////////////////////////////////////////////
/////////file name resolving policy//////////////////////////
//Because the file name in Nc card is 8.3 style ,and it dosn't support chinese words,
//but in order to make the user interface convenient , we must support the chinese
// file name in the user interface .  To resolve this conflict . We decide to do a filename mapping process.

//1. We define the first 32 bytes of a file to be  the DisplayName section .
//2.When we move a file from PC to NC card , we will create a new file in NC card ,
//the filename is "number.***" , number is the sum of the files in current directiory .
//Then , we should open this newly created file and write the source filename into the DisplayName section .
// at last , copy the source file's contain into the newly created file in Nc card.




BOOL
ISFS_IsDirectory(const u8* dirName)
{
	ISFSError rc;
	int numEntries;
	rc = ISFS_ReadDir(dirName, NULL,(u32*)&numEntries);
	if (rc == ISFS_ERROR_OK) {
	     /* the file is a directory */
		 return true;
	} else if (rc == ISFS_ERROR_INVALID) {
	     /* the file is not a directory */
		 return false;
	} else if (rc == ISFS_ERROR_ACCESS) {
	    /* caller doesn't have read access */
		ATLTRACE(_T("Error: ISFS_IsDirectory doesn't have read access.\r\n"));
		return false;
	} else {
	     /* something else is wrong ... */
		 ATLTRACE(_T("Error: ISFS_IsDirectory process failed.\r\n"));
		 return false;
	}
}


