//XXX some = 0 initializations are wrong //CHECK needs verification package yaffs2.port; import yaffs2.utils.*; import yaffs2.utils.factory.PrimitiveWrapperFactory; public class yaffsfs_C implements yaffs_Device.removeObjectCallbackInterface { /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning <charles@aleph1.co.uk> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ // #include "yaffsfs.h" // #include "yaffs_guts.h" // #include "yaffscfg.h" // #include <string.h> // for memset // #include "yportenv.h" // PORT private static yaffsfs_C callbackInstance = new yaffsfs_C(); static final int YAFFSFS_MAX_SYMLINK_DEREFERENCES = 5; // #ifndef NULL // #define NULL ((void *)0) // #endif public static final String yaffsfs_c_version="$Id: yaffsfs_C.java,v 1.4 2007/09/24 13:30:33 peter.hilber Exp $"; // configurationList is the list of devices that are supported public static yaffsfs_DeviceConfiguration[] yaffsfs_configurationList; /* Some forward references */ // public static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth); // public static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj); // Handle management. // typedef struct // { // __u8 inUse:1; // this handle is in use // __u8 readOnly:1; // this handle is read only // __u8 append:1; // append only // __u8 exclusive:1; // exclusive // __u32 position; // current position in file // yaffs_Object *obj; // the object // }yaffsfs_Handle; public static yaffsfs_Handle[] yaffsfs_handle; static { yaffsfs_handle = new yaffsfs_Handle[CFG_H.YAFFSFS_N_HANDLES]; for (int i = 0; i < yaffsfs_handle.length; i++) yaffsfs_handle[i] = new yaffsfs_Handle(); } // yaffsfs_InitHandle // / Inilitalise handles on start-up. // public static int yaffsfs_InitHandles() { int i; for(i = 0; i < CFG_H.YAFFSFS_N_HANDLES; i++) { yaffsfs_handle[i].inUse = false; yaffsfs_handle[i].obj = null; } return 0; } public static yaffsfs_Handle yaffsfs_GetHandlePointer(int h) { if(h < 0 || h >= CFG_H.YAFFSFS_N_HANDLES) { return null; } return yaffsfs_handle[h]; } public static yaffs_Object yaffsfs_GetHandleObject(int handle) { yaffsfs_Handle h = yaffsfs_GetHandlePointer(handle); if(h != null && h.inUse) { return h.obj; } return null; } // yaffsfs_GetHandle // Grab a handle (when opening a file) // public static int yaffsfs_GetHandle() { int i; yaffsfs_Handle h; for(i = 0; i < CFG_H.YAFFSFS_N_HANDLES; i++) { h = yaffsfs_GetHandlePointer(i); if(!(h != null)) { // todo bug: should never happen } if(!h.inUse) { Unix.memset(h/*,0,sizeof(yaffsfs_Handle)*/ ); h.inUse=true; return i; } } return -1; } // yaffs_PutHandle // Let go of a handle (when closing a file) // public static int yaffsfs_PutHandle(int handle) { yaffsfs_Handle h = yaffsfs_GetHandlePointer(handle); if(h != null) { h.inUse = false; h.obj = null; } return 0; } // Stuff to search for a directory from a path public static boolean yaffsfs_Match(byte a, byte b) { // case sensitive return (a == b); } // yaffsfs_FindDevice // yaffsfs_FindRoot // Scan the configuration list to find the root. // Curveballs: Should match paths that end in '/' too // Curveball2 Might have "/x/ and "/x/y". Need to return the longest match public static yaffs_Device yaffsfs_FindDevice(byte[] path, int pathIndex, /*char ***/ ArrayPointer restOfPath) { yaffsfs_DeviceConfiguration[] cfg = yaffsfs_configurationList; int cfgIndex = 0; byte[] leftOver; int leftOverIndex; byte[] p; int pIndex; yaffs_Device retval = null; int thisMatchLength; int longestMatch = -1; // Check all configs, choose the one that: // 1) Actually matches a prefix (ie /a amd /abc will not match // 2) Matches the longest. while(cfg != null && cfg[cfgIndex].prefix != null && cfg[cfgIndex].dev != null) { leftOver = path; leftOverIndex = pathIndex; p = cfg[cfgIndex].prefix; pIndex = cfg[cfgIndex].prefixIndex; thisMatchLength = 0; while(p[pIndex] != 0 && //unmatched part of prefix Unix.strcmp(p,pIndex,new byte[]{'/',0},0) != 0 && // the rest of the prefix is not / (to catch / at end) leftOver[leftOverIndex] != 0 && yaffsfs_Match(p[pIndex],leftOver[leftOverIndex])) { pIndex++; leftOverIndex++; thisMatchLength++; } if((!(p[pIndex] != 0) || Unix.strcmp(p,pIndex,new byte[]{'/',0},0) == 0) && // end of prefix (!(leftOver[leftOverIndex] != 0) || leftOver[leftOverIndex] == '/') && // no more in this path name part (thisMatchLength > longestMatch)) { // Matched prefix restOfPath.array = /*(char *)*/ leftOver; restOfPath.index = leftOverIndex; retval = cfg[cfgIndex].dev; longestMatch = thisMatchLength; } cfgIndex++; } return retval; } public static yaffs_Object yaffsfs_FindRoot(byte[] path, int pathIndex, /*char ***/ ArrayPointer restOfPath) { yaffs_Device dev; dev= yaffsfs_FindDevice(path,pathIndex,restOfPath); if(dev != null && dev.subField2.isMounted) { return dev.rootDir; } return null; } public static yaffs_Object yaffsfs_FollowLink(yaffs_Object obj,int symDepth) { while(obj != null && obj.variantType == Guts_H.YAFFS_OBJECT_TYPE_SYMLINK) { byte[] alias = obj.variant.symLinkVariant().alias; int aliasIndex = obj.variant.symLinkVariant().aliasIndex; if(alias[aliasIndex] == '/') { // Starts with a /, need to scan from root up obj = yaffsfs_FindObject(null,alias,aliasIndex,symDepth++); } else { // Relative to here, so use the parent of the symlink as a start obj = yaffsfs_FindObject(obj.parent,alias,aliasIndex,symDepth++); } } return obj; } // yaffsfs_FindDirectory // Parse a path to determine the directory and the name within the directory. // // eg. "/data/xx/ff" -. puts name="ff" and returns the directory "/data/xx" public static yaffs_Object yaffsfs_DoFindDirectory(yaffs_Object startDir, byte[] path, int pathIndex, /*char ***/ ArrayPointer name,int symDepth) { yaffs_Object dir; byte[] restOfPath; int restOfPathIndex; byte[] str = new byte[Guts_H.YAFFS_MAX_NAME_LENGTH+1]; final int strIndex = 0; int i; if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) { return null; } if(startDir != null) { dir = startDir; restOfPath = /*(char *)*/ path; restOfPathIndex = pathIndex; } else { ArrayPointer restOfPathPointer = new ArrayPointer(); dir = yaffsfs_FindRoot(path,pathIndex,restOfPathPointer); restOfPath = restOfPathPointer.array; restOfPathIndex = restOfPathPointer.index; } while(dir != null) { // parse off /. // curve ball: also throw away surplus '/' // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" while(restOfPath[restOfPathIndex] == '/') { restOfPathIndex++; // get rid of '/' } name.array = restOfPath; name.index = restOfPathIndex; i = 0; while(restOfPath[restOfPathIndex] != 0 && restOfPath[restOfPathIndex] != '/') { if (i < Guts_H.YAFFS_MAX_NAME_LENGTH) { str[strIndex+i] = restOfPath[restOfPathIndex]; str[strIndex+i+1] = '\0'; i++; } restOfPathIndex++; } if(!(restOfPath[restOfPathIndex] != 0)) { // got to the end of the string return dir; } else { if(Unix.strcmp(str,strIndex,new byte[]{'.',0},0) == 0) { // Do nothing } else if(Unix.strcmp(str,strIndex,new byte[]{'.','.',0},0) == 0) { dir = dir.parent; } else { dir = yaffs_guts_C.yaffs_FindObjectByName(dir,str,strIndex); while(dir != null && dir.variantType == Guts_H.YAFFS_OBJECT_TYPE_SYMLINK) { dir = yaffsfs_FollowLink(dir,symDepth); } if(dir != null && dir.variantType != Guts_H.YAFFS_OBJECT_TYPE_DIRECTORY) { dir = null; } } } } // directory did not exist. return null; } public static yaffs_Object yaffsfs_FindDirectory(yaffs_Object relativeDirectory, byte[] path, int pathIndex,/*char ***/ ArrayPointer name,int symDepth) { return yaffsfs_DoFindDirectory(relativeDirectory,path,pathIndex,name,symDepth); } // yaffsfs_FindObject turns a path for an existing object into the object public static yaffs_Object yaffsfs_FindObject(yaffs_Object relativeDirectory, byte[] path, int pathIndex, int symDepth) { yaffs_Object dir; byte[] name; int nameIndex; ArrayPointer namePointer = new ArrayPointer(); dir = yaffsfs_FindDirectory(relativeDirectory,path,pathIndex,namePointer,symDepth); name = namePointer.array; nameIndex = namePointer.index; if(dir != null && name[nameIndex] != 0) { return yaffs_guts_C.yaffs_FindObjectByName(dir,name,nameIndex); } return dir; } public static int yaffs_open(byte[] path, int pathIndex, int oflag, int mode) { yaffs_Object obj = null; yaffs_Object dir = null; byte[] name; int nameIndex; int handle = -1; yaffsfs_Handle h = null; boolean alreadyOpen = false; boolean alreadyExclusive = false; boolean openDenied = false; int symDepth = 0; boolean errorReported = false; int i; // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR yaffs2.utils.Globals.configuration.yaffsfs_Lock(); handle = yaffsfs_GetHandle(); if(handle >= 0) { h = yaffsfs_GetHandlePointer(handle); // try to find the exisiting object obj = yaffsfs_FindObject(null,path,pathIndex,0); if(obj != null && obj.variantType == Guts_H.YAFFS_OBJECT_TYPE_SYMLINK) { obj = yaffsfs_FollowLink(obj,symDepth++); } if(obj != null) { // Check if the object is already in use alreadyOpen = alreadyExclusive = false; // for(i = 0; i <= YAFFSFS_N_HANDLES; i++) // PORT a yaffs bug imho for(i = 0; i < CFG_H.YAFFSFS_N_HANDLES; i++) { if(i != handle && yaffsfs_handle[i].inUse && obj == yaffsfs_handle[i].obj) { alreadyOpen = true; if(yaffsfs_handle[i].exclusive) { alreadyExclusive = true; } } } if(((oflag & yaffsfs_H.O_EXCL) != 0 && alreadyOpen) || alreadyExclusive) { openDenied = true; } // Open should fail if O_CREAT and yaffsfs_H.O_EXCL are specified if((oflag & yaffsfs_H.O_EXCL) != 0 && (oflag & yaffsfs_H.O_CREAT) != 0) { openDenied = true; yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EEXIST); errorReported = true; } // Check file permissions if( (oflag & (yaffsfs_H.O_RDWR | yaffsfs_H.O_WRONLY)) == 0 && // ie O_RDONLY !((obj.yst_mode & yaffsfs_H.S_IREAD) != 0)) { openDenied = true; } if( (oflag & yaffsfs_H.O_RDWR) != 0 && !((obj.yst_mode & yaffsfs_H.S_IREAD) != 0)) { openDenied = true; } if( (oflag & (yaffsfs_H.O_RDWR | yaffsfs_H.O_WRONLY)) != 0 && !((obj.yst_mode & yaffsfs_H.S_IWRITE) != 0)) { openDenied = true; } } else if((oflag & yaffsfs_H.O_CREAT) != 0) { // Let's see if we can create this fil ArrayPointer namePointer = new ArrayPointer(); dir = yaffsfs_FindDirectory(null,path,pathIndex,namePointer,0); name = namePointer.array; nameIndex = namePointer.index; if(dir != null) { obj = yaffs_guts_C.yaffs_MknodFile(dir,name,nameIndex,mode,0,0); } else { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOTDIR); } } if(obj != null && !openDenied) { h.obj = obj; h.inUse = true; h.readOnly = (oflag & (yaffsfs_H.O_WRONLY | yaffsfs_H.O_RDWR)) != 0 ? false : true; h.append = (oflag & yaffsfs_H.O_APPEND) != 0 ? true : false; h.exclusive = (oflag & yaffsfs_H.O_EXCL) != 0 ? true : false; h.position = 0; obj.inUse++; if((oflag & yaffsfs_H.O_TRUNC) != 0 && !h.readOnly) { //todo truncate yaffs_guts_C.yaffs_ResizeFile(obj,0); } } else { yaffsfs_PutHandle(handle); if(!errorReported) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EACCESS); errorReported = true; } handle = -1; } } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return handle; } public static int yaffs_close(int fd) { yaffsfs_Handle h = null; int retVal = 0; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); h = yaffsfs_GetHandlePointer(fd); if(h != null && h.inUse) { // clean up yaffs_guts_C.yaffs_FlushFile(h.obj,true); h.obj.inUse--; if(h.obj.inUse <= 0 && h.obj.sub.unlinked) { yaffs_guts_C.yaffs_DeleteFile(h.obj); } yaffsfs_PutHandle(fd); retVal = 0; } else { // bad handle yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); retVal = -1; } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffs_read(int fd, /*void **/ byte[] buf, int bufIndex, /*unsigned int*/ int nbyte) { yaffsfs_Handle h = null; yaffs_Object obj = null; int pos = 0; int nRead = -1; int maxRead; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); h = yaffsfs_GetHandlePointer(fd); obj = yaffsfs_GetHandleObject(fd); if(!(h != null) || !(obj != null)) { // bad handle yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); } else if(h != null && obj != null) { pos= h.position; if(yaffs_guts_C.yaffs_GetObjectFileLength(obj) > pos) { maxRead = yaffs_guts_C.yaffs_GetObjectFileLength(obj) - pos; } else { maxRead = 0; } if(nbyte > maxRead) { nbyte = maxRead; } if(nbyte > 0) { nRead = yaffs_guts_C.yaffs_ReadDataFromFile(obj,buf,bufIndex,pos,nbyte); if(nRead >= 0) { h.position = pos + nRead; } else { //todo error } } else { nRead = 0; } } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return (nRead >= 0) ? nRead : -1; } public static int yaffs_write(int fd, /*const void **/ byte[] buf, int bufIndex, /*unsigned int*/ int nbyte) { yaffsfs_Handle h = null; yaffs_Object obj = null; int pos = 0; int nWritten = -1; boolean writeThrough = false; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); h = yaffsfs_GetHandlePointer(fd); obj = yaffsfs_GetHandleObject(fd); if(!(h != null) || !(obj != null)) { // bad handle yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); } else if( h != null && obj != null && h.readOnly) { // todo error } else if( h != null && obj != null) { if(h.append) { pos = yaffs_guts_C.yaffs_GetObjectFileLength(obj); } else { pos = h.position; } nWritten = yaffs_guts_C.yaffs_WriteDataToFile(obj,buf,bufIndex,pos,nbyte,writeThrough); if(nWritten >= 0) { h.position = pos + nWritten; } else { //todo error } } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return (nWritten >= 0) ? nWritten : -1; } public static int yaffs_truncate(int fd, /*off_t*/ int newSize) { yaffsfs_Handle h = null; yaffs_Object obj = null; int result = 0; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); h = yaffsfs_GetHandlePointer(fd); obj = yaffsfs_GetHandleObject(fd); if(!(h != null) || !(obj != null)) { // bad handle yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); } else { // resize the file result = yaffs_guts_C.yaffs_ResizeFile(obj,newSize); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return (result != 0) ? 0 : -1; } /*off_t*/ public static int yaffs_lseek(int fd, /*off_t*/ int offset, int whence) { yaffsfs_Handle h = null; yaffs_Object obj = null; int pos = -1; int fSize = -1; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); h = yaffsfs_GetHandlePointer(fd); obj = yaffsfs_GetHandleObject(fd); if(!(h != null) || !(obj != null)) { // bad handle yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); } else if(whence == yaffsfs_H.SEEK_SET) { if(offset >= 0) { pos = offset; } } else if(whence ==yaffsfs_H. SEEK_CUR) { if( (h.position + offset) >= 0) { pos = (h.position + offset); } } else if(whence == yaffsfs_H.SEEK_END) { fSize = yaffs_guts_C.yaffs_GetObjectFileLength(obj); if(fSize >= 0 && (fSize + offset) >= 0) { pos = fSize + offset; } } if(pos >= 0) { h.position = pos; } else { // todo error } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return pos; } public static int yaffsfs_DoUnlink(byte[] path, int pathIndex, boolean isDirectory) { yaffs_Object dir = null; yaffs_Object obj = null; byte[] name; int nameIndex; boolean result = Guts_H.YAFFS_FAIL; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); obj = yaffsfs_FindObject(null,path,pathIndex,0); ArrayPointer namePointer = new ArrayPointer(); dir = yaffsfs_FindDirectory(null,path,pathIndex,namePointer,0); name = namePointer.array; nameIndex = namePointer.index; if(!(dir != null)) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOTDIR); } else if(!(obj != null)) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOENT); } else if(!isDirectory && obj.variantType == Guts_H.YAFFS_OBJECT_TYPE_DIRECTORY) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EISDIR); } else if(isDirectory && obj.variantType != Guts_H.YAFFS_OBJECT_TYPE_DIRECTORY) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOTDIR); } else { result = yaffs_guts_C.yaffs_Unlink(dir,name,nameIndex); if(result == Guts_H.YAFFS_FAIL && isDirectory) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOTEMPTY); } } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); // todo error return (result == Guts_H.YAFFS_FAIL) ? -1 : 0; } public static int yaffs_rmdir(byte[] path, int pathIndex) { return yaffsfs_DoUnlink(path,pathIndex,true); } public static int yaffs_unlink(byte[] path, int pathIndex) { return yaffsfs_DoUnlink(path,pathIndex,false); } public static int yaffs_rename(byte[] oldPath, int oldPathIndex, byte[] newPath, int newPathIndex) { yaffs_Object olddir = null; yaffs_Object newdir = null; yaffs_Object obj = null; byte[] oldname; int oldnameIndex; byte[] newname; int newnameIndex; boolean result= Guts_H.YAFFS_FAIL; boolean renameAllowed = true; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); ArrayPointer oldnamePointer = new ArrayPointer(); olddir = yaffsfs_FindDirectory(null,oldPath,oldPathIndex,oldnamePointer,0); oldname = oldnamePointer.array; oldnameIndex = oldnamePointer.index; ArrayPointer newnamePointer = new ArrayPointer(); newdir = yaffsfs_FindDirectory(null,newPath,newPathIndex,newnamePointer,0); newname = newnamePointer.array; newnameIndex = newnamePointer.index; obj = yaffsfs_FindObject(null,oldPath,oldPathIndex,0); if(!(olddir != null) || !(newdir != null) || !(obj != null)) { // bad file yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); renameAllowed = false; } else if(olddir.myDev != newdir.myDev) { // oops must be on same device // todo error yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EXDEV); renameAllowed = false; } else if(obj != null && obj.variantType == Guts_H.YAFFS_OBJECT_TYPE_DIRECTORY) { // It is a directory, check that it is not being renamed to // being its own decendent. // Do this by tracing from the new directory back to the root, checking for obj yaffs_Object xx = newdir; while( renameAllowed && xx != null) { if(xx == obj) { renameAllowed = false; } xx = xx.parent; } if(!renameAllowed) yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EACCESS); } if(renameAllowed) { result = yaffs_guts_C.yaffs_RenameObject(olddir,oldname,oldnameIndex,newdir,newname,newnameIndex); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return (result == Guts_H.YAFFS_FAIL) ? -1 : 0; } public static int yaffsfs_DoStat(yaffs_Object obj, yaffs_stat buf) { int retVal = -1; if(obj != null) { obj = yaffs_guts_C.yaffs_GetEquivalentObject(obj); } if(obj != null && buf != null) { buf.st_dev = (int)obj.myDev.subField1.genericDevice; buf.st_ino = obj.objectId; buf.st_mode = obj.yst_mode & ~yaffsfs_H.S_IFMT; // clear out file type bits if(obj.variantType == Guts_H.YAFFS_OBJECT_TYPE_DIRECTORY) { buf.st_mode |= Unix.S_IFDIR; } else if(obj.variantType == Guts_H.YAFFS_OBJECT_TYPE_SYMLINK) { buf.st_mode |= yaffsfs_H.S_IFLNK; } else if(obj.variantType == Guts_H.YAFFS_OBJECT_TYPE_FILE) { buf.st_mode |= yaffsfs_H.S_IFREG; } buf.st_nlink = yaffs_guts_C.yaffs_GetObjectLinkCount(obj); buf.st_uid = 0; buf.st_gid = 0;; buf.st_rdev = obj.yst_rdev; buf.st_size = yaffs_guts_C.yaffs_GetObjectFileLength(obj); buf.st_blksize = obj.myDev.subField1.nDataBytesPerChunk; buf.st_blocks = (buf.st_size + buf.st_blksize -1)/buf.st_blksize; buf.yst_atime = obj.yst_atime; buf.yst_ctime = obj.yst_ctime; buf.yst_mtime = obj.yst_mtime; retVal = 0; } return retVal; } public static int yaffsfs_DoStatOrLStat(byte[] path, int pathIndex, yaffs_stat buf, boolean doLStat) { yaffs_Object obj; int retVal = -1; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); obj = yaffsfs_FindObject(null,path,pathIndex,0); if(!doLStat && obj != null) { obj = yaffsfs_FollowLink(obj,0); } if(obj != null) { retVal = yaffsfs_DoStat(obj,buf); } else { // todo error not found yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOENT); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffs_stat(byte[] path, int pathIndex, yaffs_stat buf) { return yaffsfs_DoStatOrLStat(path,pathIndex,buf,false); } public static int yaffs_lstat(byte[] path, int pathIndex, yaffs_stat buf) { return yaffsfs_DoStatOrLStat(path,pathIndex,buf,true); } public static int yaffs_fstat(int fd, yaffs_stat buf) { yaffs_Object obj; int retVal = -1; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); obj = yaffsfs_GetHandleObject(fd); if(obj != null) { retVal = yaffsfs_DoStat(obj,buf); } else { // bad handle yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffsfs_DoChMod(yaffs_Object obj,/*mode_t*/ int mode) { boolean result = false; if(obj != null) { obj = yaffs_guts_C.yaffs_GetEquivalentObject(obj); } if(obj != null) { obj.yst_mode = mode; obj.dirty = true; result = yaffs_guts_C.yaffs_FlushFile(obj,false); } return result == Guts_H.YAFFS_OK ? 0 : -1; } public static int yaffs_chmod(byte[] path, int pathIndex, /*mode_t*/int mode) { yaffs_Object obj; int retVal = -1; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); obj = yaffsfs_FindObject(null,path,pathIndex,0); if(obj != null) { retVal = yaffsfs_DoChMod(obj,mode); } else { // todo error not found yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOENT); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffs_fchmod(int fd, /*mode_t*/ int mode) { yaffs_Object obj; int retVal = -1; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); obj = yaffsfs_GetHandleObject(fd); if(obj != null) { retVal = yaffsfs_DoChMod(obj,mode); } else { // bad handle yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffs_mkdir(byte[] path, int pathIndex, /*mode_t*/ int mode) { yaffs_Object parent = null; yaffs_Object dir = null; byte[] name; int nameIndex; int retVal= -1; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); ArrayPointer namePointer = new ArrayPointer(); parent = yaffsfs_FindDirectory(null,path,pathIndex,namePointer,0); name = namePointer.array; nameIndex = namePointer.index; if(parent != null) dir = yaffs_guts_C.yaffs_MknodDirectory(parent,name,nameIndex,mode,0,0); if(dir != null) { retVal = 0; } else { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOSPC); // just assume no space for now retVal = -1; } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffs_mount(byte[] path, int pathIndex) { int retVal=-1; boolean result=Guts_H.YAFFS_FAIL; yaffs_Device dev=null; // byte[] dummy; int dummyIndex; yportenv.T(yportenv.YAFFS_TRACE_ALWAYS,"yaffs: Mounting %a\n",PrimitiveWrapperFactory.get(path),PrimitiveWrapperFactory.get(pathIndex)); yaffs2.utils.Globals.configuration.yaffsfs_Lock(); ArrayPointer dummyPointer = new ArrayPointer(); dev = yaffsfs_FindDevice(path,pathIndex,dummyPointer); // dummy = dummyPointer.array; dummyIndex = dummyPointer.index; if(dev != null) { if(!dev.subField2.isMounted) { result = yaffs_guts_C.yaffs_GutsInitialise(dev); if(result == Guts_H.YAFFS_FAIL) { // todo error - mount failed yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOMEM); } retVal = result ? 0 : -1; } else { //todo error - already mounted. yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBUSY); } } else { // todo error - no device yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENODEV); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffs_unmount(byte[] path, int pathIndex) { int retVal=-1; yaffs_Device dev=null; // byte[] dummy; int dummyIndex; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); ArrayPointer dummyPointer = new ArrayPointer(); dev = yaffsfs_FindDevice(path,pathIndex,dummyPointer); // dummy = dummyPointer.array; dummyIndex = dummyPointer.index; if(dev != null) { if(dev.subField2.isMounted) { int i; boolean inUse = false; yaffs_guts_C.yaffs_FlushEntireDeviceCache(dev); yaffs_guts_C.yaffs_CheckpointSave(dev); for(i = 0; i < CFG_H.YAFFSFS_N_HANDLES && !inUse; i++) { if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj.myDev == dev) { inUse = true; // the device is in use, can't unmount } } if(!inUse) { yaffs_guts_C.yaffs_Deinitialise(dev); retVal = 0; } else { // todo error can't unmount as files are open yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBUSY); } } else { //todo error - not mounted. yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EINVAL); } } else { // todo error - no device yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENODEV); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } // XXX type public static /*loff_t*/ int yaffs_freespace(byte[] path, int pathIndex) { /*loff_t*/ int retVal=-1; yaffs_Device dev=null; // byte[] dummy; int dummyIndex; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); ArrayPointer dummyPointer = new ArrayPointer(); dev = yaffsfs_FindDevice(path,pathIndex,dummyPointer); // dummy = dummyPointer.array; dummyIndex = dummyPointer.index; if(dev != null && dev.subField2.isMounted) { retVal = yaffs_guts_C.yaffs_GetNumberOfFreeChunks(dev); retVal = retVal * dev.subField1.nDataBytesPerChunk; } else { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EINVAL); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static void yaffs_initialise(yaffsfs_DeviceConfiguration[] cfgList) { yaffsfs_DeviceConfiguration[] cfg; int cfgIndex; yaffsfs_configurationList = cfgList; yaffsfs_InitHandles(); cfg = yaffsfs_configurationList; cfgIndex = 0; while(cfg != null && cfg[cfgIndex].prefix != null && cfg[cfgIndex].dev != null) { cfg[cfgIndex].dev.subField2.isMounted = false; cfg[cfgIndex].dev.subField1.removeObjectCallback = callbackInstance; cfgIndex++; } } // // Directory search stuff. // // Directory search context // // NB this is an opaque structure. // typedef struct // { // __u32 magic; // yaffs_dirent de; /* directory entry being used by this dsc */ // char name[NAME_MAX+1]; /* name of directory being searched */ // yaffs_Object *dirObj; /* ptr to directory being searched */ // yaffs_Object *nextReturn; /* obj to be returned by next readddir */ // int offset; // struct list_head others; // } yaffsfs_DirectorySearchContext; public static list_head search_contexts = new list_head(null); public static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext dsc) { if(dsc != null && dsc.dirObj != null && dsc.dirObj.variantType == Guts_H.YAFFS_OBJECT_TYPE_DIRECTORY){ dsc.offset = 0; if(devextras.list_empty(dsc.dirObj.variant.directoryVariant.children)){ dsc.nextReturn = null; } else { dsc.nextReturn = /*list_entry(dsc.dirObj.variant.directoryVariant.children.next, yaffs_Object,siblings);*/ (yaffs_Object)dsc.dirObj.variant.directoryVariant.children.next().list_entry; } } else { /* Hey someone isn't playing nice! */ } } public static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext dsc) { if(dsc != null && dsc.dirObj != null && dsc.dirObj.variantType == Guts_H.YAFFS_OBJECT_TYPE_DIRECTORY){ if( dsc.nextReturn == null || devextras.list_empty(dsc.dirObj.variant.directoryVariant.children)){ dsc.nextReturn = null; } else { list_head next = dsc.nextReturn.siblings.next(); if( next == dsc.dirObj.variant.directoryVariant.children) dsc.nextReturn = null; /* end of list */ else dsc.nextReturn = /*list_entry(next,yaffs_Object,siblings)*/(yaffs_Object)next.list_entry; } } else { /* Hey someone isn't playing nice! */ } } public void yaffsfs_RemoveObjectCallback(yaffs_Object obj) { list_head i; yaffsfs_DirectorySearchContext dsc; /* if search contexts not initilised then skip */ if(!(search_contexts.next != null)) return; /* Iteratethrough the directory search contexts. * If any are the one being removed, then advance the dsc to * the next one to prevent a hanging ptr. */ /*list_for_each(i, &search_contexts) {*/ for (i = search_contexts.next();i != search_contexts;i = i.next()) { if (i != null) { dsc = /*list_entry(i, yaffsfs_DirectorySearchContext,others);*/ (yaffsfs_DirectorySearchContext)i.list_entry; if(dsc.nextReturn == obj) yaffsfs_DirAdvance(dsc); } } } public static yaffs_DIR yaffs_opendir(byte[] dirname, int dirnameIndex) { yaffs_DIR dir = null; yaffs_Object obj = null; yaffsfs_DirectorySearchContext dsc = null; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); obj = yaffsfs_FindObject(null,dirname,dirnameIndex,0); if(obj != null && obj.variantType == Guts_H.YAFFS_OBJECT_TYPE_DIRECTORY) { dsc = /*YMALLOC(sizeof(yaffsfs_DirectorySearchContext))*/ new yaffsfs_DirectorySearchContext(); dir = (yaffs_DIR)dsc; if(dsc != null) { // Unix.memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext)); // TODO CHECK: do as serializable? Unix.memset(dsc); dsc.magic = Guts_H.YAFFS_MAGIC; dsc.dirObj = obj; Unix.strncpy(dsc.name,dsc.nameIndex,dirname,dirnameIndex,yaffsfs_H.NAME_MAX); devextras.INIT_LIST_HEAD(dsc.others); if(!(search_contexts.next != null)) devextras.INIT_LIST_HEAD(/*&*/search_contexts); devextras.list_add(/*&*/dsc.others,/*&*/search_contexts); yaffsfs_SetDirRewound(dsc); } } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return dir; } public static yaffs_dirent yaffs_readdir(yaffs_DIR dirp) { yaffsfs_DirectorySearchContext dsc = (yaffsfs_DirectorySearchContext)dirp; yaffs_dirent retVal = null; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); if(dsc != null && dsc.magic == Guts_H.YAFFS_MAGIC){ yaffs2.utils.Globals.configuration.yaffsfs_SetError(0); if(dsc.nextReturn != null){ dsc.de.d_ino = yaffs_guts_C.yaffs_GetEquivalentObject(dsc.nextReturn).objectId; dsc.de.d_dont_use = /*(unsigned)*/dsc.nextReturn; dsc.de.d_off = dsc.offset++; yaffs_guts_C.yaffs_GetObjectName(dsc.nextReturn,dsc.de.d_name,dsc.de.d_nameIndex,yaffsfs_H.NAME_MAX); if(Unix.strlen(dsc.de.d_name, dsc.de.d_nameIndex) == 0) { // this should not happen! Unix.strcpy(dsc.de.d_name,dsc.de.d_nameIndex,new byte[]{'z','z',0},0); } // dsc.de.d_reclen = sizeof(struct yaffs_dirent); // PORT ??? retVal = dsc.de; yaffsfs_DirAdvance(dsc); } else retVal = null; } else { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EBADF); } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static void yaffs_rewinddir(yaffs_DIR dirp) { yaffsfs_DirectorySearchContext dsc = (yaffsfs_DirectorySearchContext)dirp; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); yaffsfs_SetDirRewound(dsc); yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); } public static int yaffs_closedir(yaffs_DIR dirp) { yaffsfs_DirectorySearchContext dsc = (yaffsfs_DirectorySearchContext)dirp; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); dsc.magic = 0; devextras.list_del(dsc.others); /* unhook from list */ ydirectenv.YFREE(dsc); yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return 0; } // end of directory stuff public static int yaffs_symlink(byte[] oldpath, int oldpathIndex, byte[] newpath, int newpathIndex) { yaffs_Object parent = null; yaffs_Object obj; byte[] name; int nameIndex; int retVal= -1; int mode = 0; // ignore for now yaffs2.utils.Globals.configuration.yaffsfs_Lock(); ArrayPointer namePointer = new ArrayPointer(); parent = yaffsfs_FindDirectory(null,newpath,newpathIndex,namePointer,0); name = namePointer.array; nameIndex = namePointer.index; obj = yaffs_guts_C.yaffs_MknodSymLink(parent,name,nameIndex,mode,0,0,oldpath,oldpathIndex); if(obj != null) { retVal = 0; } else { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOSPC); // just assume no space for now retVal = -1; } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffs_readlink(byte[] path, int pathIndex, byte[] buf, int bufIndex, int bufsiz) { yaffs_Object obj = null; int retVal; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); obj = yaffsfs_FindObject(null,path,pathIndex,0); if(!(obj != null)) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOENT); retVal = -1; } else if(obj.variantType != Guts_H.YAFFS_OBJECT_TYPE_SYMLINK) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EINVAL); retVal = -1; } else { byte[] alias = obj.variant.symLinkVariant.alias; int aliasIndex = obj.variant.symLinkVariant.aliasIndex; Unix.memset(buf,bufIndex,(byte)0,bufsiz); Unix.strncpy(buf,bufIndex,alias,aliasIndex,bufsiz-1); retVal = 0; } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } public static int yaffs_link(byte[] oldpath, int oldpathIndex, byte[] newpath, int newpathIndex) { // Creates a link called newpath to existing oldpath yaffs_Object obj = null; yaffs_Object target = null; int retVal = 0; yaffs2.utils.Globals.configuration.yaffsfs_Lock(); obj = yaffsfs_FindObject(null,oldpath,oldpathIndex,0); target = yaffsfs_FindObject(null,newpath,newpathIndex,0); if(!(obj != null)) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOENT); retVal = -1; } else if(target != null) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EEXIST); retVal = -1; } else { yaffs_Object newdir = null; yaffs_Object link = null; byte[] newname; int newnameIndex; ArrayPointer newnamePointer = new ArrayPointer(); newdir = yaffsfs_FindDirectory(null,newpath,newpathIndex,newnamePointer,0); newname = newnamePointer.array; newnameIndex = newnamePointer.index; if(!(newdir != null)) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOTDIR); retVal = -1; } else if(newdir.myDev != obj.myDev) { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.EXDEV); retVal = -1; } if(newdir != null && Unix.strlen(newname,newnameIndex) > 0) { link = yaffs_guts_C.yaffs_Link(newdir,newname,newnameIndex,obj); if(link != null) retVal = 0; else { yaffs2.utils.Globals.configuration.yaffsfs_SetError(-yaffsfs_H.ENOSPC); retVal = -1; } } } yaffs2.utils.Globals.configuration.yaffsfs_Unlock(); return retVal; } // public static int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev); public static int yaffs_DumpDevStruct(byte[] path, int pathIndex) { // byte[] rest; int restIndex; ArrayPointer restPointer = new ArrayPointer(); yaffs_Object obj = yaffsfs_FindRoot(path,pathIndex,restPointer); // rest = restPointer.array; restIndex = restPointer.index; if(obj != null) { yaffs_Device dev = obj.myDev; Unix.xprintfArgs[0] = PrimitiveWrapperFactory.get(dev.subField3.nPageWrites); Unix.xprintfArgs[1] = PrimitiveWrapperFactory.get(dev.subField3.nPageReads); Unix.xprintfArgs[2] = PrimitiveWrapperFactory.get(dev.subField3.nBlockErasures); Unix.xprintfArgs[3] = PrimitiveWrapperFactory.get(dev.subField3.nGCCopies); Unix.xprintfArgs[4] = PrimitiveWrapperFactory.get(dev.subField3.garbageCollections); Unix.xprintfArgs[5] = PrimitiveWrapperFactory.get(dev.subField3.passiveGarbageCollections); Unix.printf("\n" + "nPageWrites.......... %d\n" + "nPageReads........... %d\n" + "nBlockErasures....... %d\n" + "nGCCopies............ %d\n" + "garbageCollections... %d\n" + "passiveGarbageColl'ns %d\n" + "\n"); } return 0; } }