diff options
Diffstat (limited to 'fs/yaffs2/yaffsfs.c')
| -rw-r--r-- | fs/yaffs2/yaffsfs.c | 3432 | 
1 files changed, 2570 insertions, 862 deletions
| diff --git a/fs/yaffs2/yaffsfs.c b/fs/yaffs2/yaffsfs.c index 111cb348c..9f1397b57 100644 --- a/fs/yaffs2/yaffsfs.c +++ b/fs/yaffs2/yaffsfs.c @@ -1,7 +1,7 @@  /*   * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.   * - * Copyright (C) 2002-2007 Aleph One Ltd. + * Copyright (C) 2002-2011 Aleph One Ltd.   *   for Toby Churchill Ltd and Brightstar Engineering   *   * Created by Charles Manning <charles@aleph1.co.uk> @@ -11,19 +11,13 @@   * published by the Free Software Foundation.   */ -/* XXX U-BOOT XXX */ -#include <common.h> -#include <malloc.h> -  #include "yaffsfs.h"  #include "yaffs_guts.h"  #include "yaffscfg.h"  #include "yportenv.h" +#include "yaffs_trace.h" -/* XXX U-BOOT XXX */ -#if 0 -#include <string.h> // for memset -#endif +#include "string.h"  #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5 @@ -31,452 +25,968 @@  #define NULL ((void *)0)  #endif +/* YAFFSFS_RW_SIZE must be a power of 2 */ +#define YAFFSFS_RW_SHIFT (13) +#define YAFFSFS_RW_SIZE  (1<<YAFFSFS_RW_SHIFT) -const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.18 2007/07/18 19:40:38 charles Exp $"; +/* Some forward references */ +static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory, +					    const YCHAR *path, +					    int symDepth, int getEquiv, +					    struct yaffs_obj **dirOut, +					    int *notDir, int *loop); -// configurationList is the list of devices that are supported -static yaffsfs_DeviceConfiguration *yaffsfs_configurationList; +static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj); +unsigned int yaffs_wr_attempts; -/* Some forward references */ -static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth); -static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj); +/* + * Handle management. + * There are open inodes in struct yaffsfs_Inode. + * There are open file descriptors in yaffsfs_FileDes. + * There are open handles in yaffsfs_FileDes. + * + * Things are structured this way to be like the Linux VFS model + * so that interactions with the yaffs guts calls are similar. + * That means more common code paths and less special code. + * That means better testing etc. + * + * We have 3 layers because: + * A handle is different than an fd because you can use dup() + * to create a new handle that accesses the *same* fd. The two + * handles will use the same offset (part of the fd). We only close + * down the fd when there are no more handles accessing it. + * + * More than one fd can currently access one file, but each fd + * has its own permsiions and offset. + */ +struct yaffsfs_Inode { +	int count;		/* Number of handles accessing this inode */ +	struct yaffs_obj *iObj; +}; -// Handle management. -// +struct yaffsfs_FileDes { +	u8 reading:1; +	u8 writing:1; +	u8 append:1; +	u8 shareRead:1; +	u8 shareWrite:1; +	int inodeId:12;		/* Index to corresponding yaffsfs_Inode */ +	int handleCount:10;	/* Number of handles for this fd */ +	loff_t position;	/* current position in file */ +}; +struct yaffsfs_Handle { +	short int fdId; +	short int useCount; +}; -unsigned int yaffs_wr_attempts; -typedef struct +struct yaffsfs_DirSearchContxt { +	struct yaffs_dirent de;	/* directory entry */ +	YCHAR name[NAME_MAX + 1];	/* name of directory being searched */ +	struct yaffs_obj *dirObj;	/* ptr to directory being searched */ +	struct yaffs_obj *nextReturn;	/* obj  returned by next readddir */ +	struct list_head others; +	int offset:20; +	unsigned inUse:1; +}; + +static struct yaffsfs_DirSearchContxt yaffsfs_dsc[YAFFSFS_N_DSC]; +static struct yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES]; +static struct yaffsfs_FileDes yaffsfs_fd[YAFFSFS_N_HANDLES]; +static struct yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES]; + +static int yaffsfs_handlesInitialised; + +unsigned yaffs_set_trace(unsigned tm)  { -	__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; +	yaffs_trace_mask = tm; +	return yaffs_trace_mask; +} +unsigned yaffs_get_trace(void) +{ +	return yaffs_trace_mask; +} -static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES]; +/* + * yaffsfs_InitHandle + * Inilitalise handle management on start-up. + */ -// yaffsfs_InitHandle -/// Inilitalise handles on start-up. -// -static int yaffsfs_InitHandles(void) +static void yaffsfs_InitHandles(void)  {  	int i; -	for(i = 0; i < YAFFSFS_N_HANDLES; i++) -	{ -		yaffsfs_handle[i].inUse = 0; -		yaffsfs_handle[i].obj = NULL; -	} -	return 0; +	if (yaffsfs_handlesInitialised) +		return; + +	memset(yaffsfs_inode, 0, sizeof(yaffsfs_inode)); +	memset(yaffsfs_fd, 0, sizeof(yaffsfs_fd)); +	memset(yaffsfs_handle, 0, sizeof(yaffsfs_handle)); +	memset(yaffsfs_dsc, 0, sizeof(yaffsfs_dsc)); + +	for (i = 0; i < YAFFSFS_N_HANDLES; i++) +		yaffsfs_fd[i].inodeId = -1; +	for (i = 0; i < YAFFSFS_N_HANDLES; i++) +		yaffsfs_handle[i].fdId = -1;  } -yaffsfs_Handle *yaffsfs_GetHandlePointer(int h) +static struct yaffsfs_Handle *yaffsfs_HandleToPointer(int h)  { -	if(h < 0 || h >= YAFFSFS_N_HANDLES) -	{ -		return NULL; -	} +	if (h >= 0 && h < YAFFSFS_N_HANDLES) +		return &yaffsfs_handle[h]; +	return NULL; +} + +static struct yaffsfs_FileDes *yaffsfs_HandleToFileDes(int handle) +{ +	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); + +	if (h && h->useCount > 0 && h->fdId >= 0 && h->fdId < YAFFSFS_N_HANDLES) +		return &yaffsfs_fd[h->fdId]; -	return &yaffsfs_handle[h]; +	return NULL;  } -yaffs_Object *yaffsfs_GetHandleObject(int handle) +static struct yaffsfs_Inode *yaffsfs_HandleToInode(int handle)  { -	yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle); +	struct yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle); -	if(h && h->inUse) -	{ -		return h->obj; -	} +	if (fd && fd->handleCount > 0 && +	    fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES) +		return &yaffsfs_inode[fd->inodeId]; + +	return NULL; +} + +static struct yaffs_obj *yaffsfs_HandleToObject(int handle) +{ +	struct yaffsfs_Inode *in = yaffsfs_HandleToInode(handle); + +	if (in) +		return in->iObj;  	return NULL;  } +/* + * yaffsfs_FindInodeIdForObject + * Find the inode entry for an object, if it exists. + */ + +static int yaffsfs_FindInodeIdForObject(struct yaffs_obj *obj) +{ +	int i; +	int ret = -1; + +	if (obj) +		obj = yaffs_get_equivalent_obj(obj); -//yaffsfs_GetHandle -// Grab a handle (when opening a file) -// +	/* Look for it in open inode table */ +	for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) { +		if (yaffsfs_inode[i].iObj == obj) +			ret = i; +	} +	return ret; +} -static int yaffsfs_GetHandle(void) +/* + * yaffsfs_GetInodeIdForObject + * Grab an inode entry when opening a new inode. + */ +static int yaffsfs_GetInodeIdForObject(struct yaffs_obj *obj)  {  	int i; -	yaffsfs_Handle *h; +	int ret; +	struct yaffsfs_Inode *in = NULL; + +	if (obj) +		obj = yaffs_get_equivalent_obj(obj); + +	ret = yaffsfs_FindInodeIdForObject(obj); + +	for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) { +		if (!yaffsfs_inode[i].iObj) +			ret = i; +	} + +	if (ret >= 0) { +		in = &yaffsfs_inode[ret]; +		if (!in->iObj) +			in->count = 0; +		in->iObj = obj; +		in->count++; +	} + +	return ret; +} + +static int yaffsfs_CountHandles(struct yaffs_obj *obj) +{ +	int i = yaffsfs_FindInodeIdForObject(obj); + +	if (i >= 0) +		return yaffsfs_inode[i].count; +	else +		return 0; +} + +static void yaffsfs_ReleaseInode(struct yaffsfs_Inode *in) +{ +	struct yaffs_obj *obj; + +	obj = in->iObj; + +	if (obj->unlinked) +		yaffs_del_obj(obj); + +	obj->my_inode = NULL; +	in->iObj = NULL; -	for(i = 0; i < YAFFSFS_N_HANDLES; i++) -	{ -		h = yaffsfs_GetHandlePointer(i); -		if(!h) -		{ -			// todo bug: should never happen +} + +static void yaffsfs_PutInode(int inodeId) +{ +	if (inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES) { +		struct yaffsfs_Inode *in = &yaffsfs_inode[inodeId]; +		in->count--; +		if (in->count <= 0) { +			yaffsfs_ReleaseInode(in); +			in->count = 0;  		} -		if(!h->inUse) -		{ -			memset(h,0,sizeof(yaffsfs_Handle)); -			h->inUse=1; +	} +} + +static int yaffsfs_NewHandle(struct yaffsfs_Handle **hptr) +{ +	int i; +	struct yaffsfs_Handle *h; + +	for (i = 0; i < YAFFSFS_N_HANDLES; i++) { +		h = &yaffsfs_handle[i]; +		if (h->useCount < 1) { +			memset(h, 0, sizeof(struct yaffsfs_Handle)); +			h->fdId = -1; +			h->useCount = 1; +			if (hptr) +				*hptr = h;  			return i;  		}  	}  	return -1;  } -// yaffs_PutHandle -// Let go of a handle (when closing a file) -// -static int yaffsfs_PutHandle(int handle) +static int yaffsfs_NewHandleAndFileDes(void) +{ +	int i; +	struct yaffsfs_FileDes *fd; +	struct yaffsfs_Handle *h = NULL; +	int handle = yaffsfs_NewHandle(&h); + +	if (handle < 0) +		return -1; + +	for (i = 0; i < YAFFSFS_N_HANDLES; i++) { +		fd = &yaffsfs_fd[i]; +		if (fd->handleCount < 1) { +			memset(fd, 0, sizeof(struct yaffsfs_FileDes)); +			fd->inodeId = -1; +			fd->handleCount = 1; +			h->fdId = i; +			return handle; +		} +	} + +	/* Dump the handle because we could not get a fd */ +	h->useCount = 0; +	return -1; +} + +/* + * yaffs_get_handle + * Increase use of handle when reading/writing a file + * Also gets the file descriptor. + */ + +static int yaffsfs_GetHandle(int handle) +{ +	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); + +	if (h && h->useCount > 0) { +		h->useCount++; +		return 0; +	} +	return -1; +} + +/* + * yaffs_put_handle + * Let go of a handle when closing a file or aborting an open or + * ending a read or write. + */ + +static int yaffsfs_PutFileDes(int fdId)  { -	yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle); +	struct yaffsfs_FileDes *fd; -	if(h) -	{ -		h->inUse = 0; -		h->obj = NULL; +	if (fdId >= 0 && fdId < YAFFSFS_N_HANDLES) { +		fd = &yaffsfs_fd[fdId]; +		fd->handleCount--; +		if (fd->handleCount < 1) { +			if (fd->inodeId >= 0) { +				yaffsfs_PutInode(fd->inodeId); +				fd->inodeId = -1; +			} +		}  	}  	return 0;  } +static int yaffsfs_PutHandle(int handle) +{ +	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); + +	if (h && h->useCount > 0) { +		h->useCount--; +		if (h->useCount < 1) { +			yaffsfs_PutFileDes(h->fdId); +			h->fdId = -1; +		} +	} + +	return 0; +} +static void yaffsfs_BreakDeviceHandles(struct yaffs_dev *dev) +{ +	struct yaffsfs_FileDes *fd; +	struct yaffsfs_Handle *h; +	struct yaffs_obj *obj; +	int i; +	for (i = 0; i < YAFFSFS_N_HANDLES; i++) { +		h = yaffsfs_HandleToPointer(i); +		fd = yaffsfs_HandleToFileDes(i); +		obj = yaffsfs_HandleToObject(i); +		if (h && h->useCount > 0) { +			h->useCount = 0; +			h->fdId = 0; +		} +		if (fd && fd->handleCount > 0 && obj && obj->my_dev == dev) { +			fd->handleCount = 0; +			yaffsfs_PutInode(fd->inodeId); +			fd->inodeId = -1; +		} +	} +} -// Stuff to search for a directory from a path +/* + *  Stuff to handle names. + */ +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE +static int yaffs_toupper(YCHAR a) +{ +	if (a >= 'a' && a <= 'z') +		return (a - 'a') + 'A'; +	else +		return a; +} -int yaffsfs_Match(char a, char b) +int yaffsfs_Match(YCHAR a, YCHAR b) +{ +	return (yaffs_toupper(a) == yaffs_toupper(b)); +} +#else +int yaffsfs_Match(YCHAR a, YCHAR b)  { -	// case sensitive +	/* case sensitive */  	return (a == b);  } +#endif -// 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 -static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath) +int yaffsfs_IsPathDivider(YCHAR ch)  { -	yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList; -	const char *leftOver; -	const char *p; -	yaffs_Device *retval = NULL; +	const YCHAR *str = YAFFS_PATH_DIVIDERS; + +	while (*str) { +		if (*str == ch) +			return 1; +		str++; +	} + +	return 0; +} + +int yaffsfs_CheckNameLength(const char *name) +{ +	int retVal = 0; + +	int nameLength = yaffs_strnlen(name, YAFFS_MAX_NAME_LENGTH + 1); + +	if (nameLength == 0) { +		yaffsfs_SetError(-ENOENT); +		retVal = -1; +	} else if (nameLength > YAFFS_MAX_NAME_LENGTH) { +		yaffsfs_SetError(-ENAMETOOLONG); +		retVal = -1; +	} + +	return retVal; +} + +static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path) +{ +	YCHAR *alt_path = NULL; +	int path_length; +	int i; + +	/* +	 * We don't have a definition for max path length. +	 * We will use 3 * max name length instead. +	 */ +	*ret_path = NULL; +	path_length = yaffs_strnlen(path, (YAFFS_MAX_NAME_LENGTH + 1) * 3 + 1); + +	/* If the last character is a path divider, then we need to +	 * trim it back so that the name look-up works properly. +	 * eg. /foo/new_dir/ -> /foo/newdir +	 * Curveball: Need to handle multiple path dividers: +	 * eg. /foof/sdfse///// -> /foo/sdfse +	 */ +	if (path_length > 0 && yaffsfs_IsPathDivider(path[path_length - 1])) { +		alt_path = kmalloc(path_length + 1, 0); +		if (!alt_path) +			return -1; +		yaffs_strcpy(alt_path, path); +		for (i = path_length - 1; +		     i >= 0 && yaffsfs_IsPathDivider(alt_path[i]); i--) +			alt_path[i] = (YCHAR) 0; +	} +	*ret_path = alt_path; +	return 0; +} + +LIST_HEAD(yaffsfs_deviceList); + +/* + * yaffsfs_FindDevice + * yaffsfs_FindRoot + * Scan the configuration list to find the device + * Curveballs: Should match paths that end in '/' too + * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match + */ +static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path, +					    YCHAR **restOfPath) +{ +	struct list_head *cfg; +	const YCHAR *leftOver; +	const YCHAR *p; +	struct yaffs_dev *retval = NULL; +	struct yaffs_dev *dev = NULL;  	int thisMatchLength;  	int longestMatch = -1; +	int matching; -	// 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 && cfg->prefix && cfg->dev) -	{ +	/* +	 * Check all configs, choose the one that: +	 * 1) Actually matches a prefix (ie /a amd /abc will not match +	 * 2) Matches the longest. +	 */ +	list_for_each(cfg, &yaffsfs_deviceList) { +		dev = list_entry(cfg, struct yaffs_dev, dev_list);  		leftOver = path; -		p = cfg->prefix; +		p = dev->param.name;  		thisMatchLength = 0; +		matching = 1; -		while(*p &&  //unmatched part of prefix -		      strcmp(p,"/") && // the rest of the prefix is not / (to catch / at end) -		      *leftOver && -		      yaffsfs_Match(*p,*leftOver)) -		{ -			p++; -			leftOver++; -			thisMatchLength++; +		while (matching && *p && *leftOver) { +			/* Skip over any /s */ +			while (yaffsfs_IsPathDivider(*p)) +				p++; + +			/* Skip over any /s */ +			while (yaffsfs_IsPathDivider(*leftOver)) +				leftOver++; + +			/* Now match the text part */ +			while (matching && +			       *p && !yaffsfs_IsPathDivider(*p) && +			       *leftOver && !yaffsfs_IsPathDivider(*leftOver)) { +				if (yaffsfs_Match(*p, *leftOver)) { +					p++; +					leftOver++; +					thisMatchLength++; +				} else { +					matching = 0; +				} +			}  		} -		if((!*p || strcmp(p,"/") == 0) &&      // end of prefix -		   (!*leftOver || *leftOver == '/') && // no more in this path name part -		   (thisMatchLength > longestMatch)) -		{ -			// Matched prefix -			*restOfPath = (char *)leftOver; -			retval = cfg->dev; + +		/* Skip over any /s in leftOver */ +		while (yaffsfs_IsPathDivider(*leftOver)) +			leftOver++; + +		/*Skip over any /s in p */ +		while (yaffsfs_IsPathDivider(*p)) +			p++; + +		/* p should now be at the end of the string if fully matched */ +		if (*p) +			matching = 0; + +		if (matching && (thisMatchLength > longestMatch)) { +			/* Matched prefix */ +			*restOfPath = (YCHAR *) leftOver; +			retval = dev;  			longestMatch = thisMatchLength;  		} -		cfg++; +  	}  	return retval;  } -static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath) +static int yaffsfs_CheckPath(const YCHAR *path)  { +	int n = 0; +	int divs = 0; -	yaffs_Device *dev; - -	dev= yaffsfs_FindDevice(path,restOfPath); -	if(dev && dev->isMounted) -	{ -		return dev->rootDir; +	while (*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100) { +		if (yaffsfs_IsPathDivider(*path)) { +			n = 0; +			divs++; +		} else +			n++; +		path++;  	} + +	return (*path) ? -1 : 0; +} + +/* FindMountPoint only returns a dev entry if the path is a mount point */ +static struct yaffs_dev *yaffsfs_FindMountPoint(const YCHAR *path) +{ +	struct yaffs_dev *dev; +	YCHAR *restOfPath = NULL; + +	dev = yaffsfs_FindDevice(path, &restOfPath); +	if (dev && restOfPath && *restOfPath) +		dev = NULL; +	return dev; +} + +static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path, +					  YCHAR **restOfPath) +{ +	struct yaffs_dev *dev; + +	dev = yaffsfs_FindDevice(path, restOfPath); +	if (dev && dev->is_mounted) +		return dev->root_dir; +  	return NULL;  } -static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth) +static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj, +					    int symDepth, int *loop)  { -	while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) -	{ -		char *alias = obj->variant.symLinkVariant.alias; +	if (obj) +		obj = yaffs_get_equivalent_obj(obj); -		if(*alias == '/') -		{ -			// Starts with a /, need to scan from root up -			obj = yaffsfs_FindObject(NULL,alias,symDepth++); -		} +	while (obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { +		YCHAR *alias = obj->variant.symlink_variant.alias; + +		if (yaffsfs_IsPathDivider(*alias)) +			/* Starts with a /, need to scan from root up */ +			obj = yaffsfs_FindObject(NULL, alias, symDepth++, +						 1, NULL, NULL, loop);  		else -		{ -			// Relative to here, so use the parent of the symlink as a start -			obj = yaffsfs_FindObject(obj->parent,alias,symDepth++); -		} +			/* +			 * Relative to here so use the parent of the +			 * symlink as a start +			 */ +			obj = yaffsfs_FindObject(obj->parent, alias, symDepth++, +						 1, NULL, NULL, loop);  	}  	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" -static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const char *path,char **name,int symDepth) +/* + * 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" + */ +static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir, +						 const YCHAR *path, +						 YCHAR **name, int symDepth, +						 int *notDir, int *loop)  { -	yaffs_Object *dir; -	char *restOfPath; -	char str[YAFFS_MAX_NAME_LENGTH+1]; +	struct yaffs_obj *dir; +	YCHAR *restOfPath; +	YCHAR str[YAFFS_MAX_NAME_LENGTH + 1];  	int i; -	if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) -	{ +	if (symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) { +		if (loop) +			*loop = 1;  		return NULL;  	} -	if(startDir) -	{ +	if (startDir) {  		dir = startDir; -		restOfPath = (char *)path; -	} -	else -	{ -		dir = yaffsfs_FindRoot(path,&restOfPath); -	} +		restOfPath = (YCHAR *) path; +	} else +		dir = yaffsfs_FindRoot(path, &restOfPath); -	while(dir) -	{ -		// parse off /. -		// curve ball: also throw away surplus '/' -		// eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" -		while(*restOfPath == '/') -		{ -			restOfPath++; // get rid of '/' -		} +	while (dir) { +		/* +		 * parse off /. +		 * curve ball: also throw away surplus '/' +		 * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" +		 */ +		while (yaffsfs_IsPathDivider(*restOfPath)) +			restOfPath++;	/* get rid of '/' */  		*name = restOfPath;  		i = 0; -		while(*restOfPath && *restOfPath != '/') -		{ -			if (i < YAFFS_MAX_NAME_LENGTH) -			{ +		while (*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)) { +			if (i < YAFFS_MAX_NAME_LENGTH) {  				str[i] = *restOfPath; -				str[i+1] = '\0'; +				str[i + 1] = '\0';  				i++;  			}  			restOfPath++;  		} -		if(!*restOfPath) -		{ -			// got to the end of the string +		if (!*restOfPath) +			/* got to the end of the string */  			return dir; -		} -		else -		{ -			if(strcmp(str,".") == 0) -			{ -				// Do nothing -			} -			else if(strcmp(str,"..") == 0) -			{ +		else { +			if (yaffs_strcmp(str, _Y(".")) == 0) { +				/* Do nothing */ +			} else if (yaffs_strcmp(str, _Y("..")) == 0) {  				dir = dir->parent; -			} -			else -			{ -				dir = yaffs_FindObjectByName(dir,str); - -				while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK) -				{ - -					dir = yaffsfs_FollowLink(dir,symDepth); +			} else { +				dir = yaffs_find_by_name(dir, str); -				} +				dir = yaffsfs_FollowLink(dir, symDepth, loop); -				if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) -				{ +				if (dir && dir->variant_type != +				    YAFFS_OBJECT_TYPE_DIRECTORY) { +					if (notDir) +						*notDir = 1;  					dir = NULL;  				} +  			}  		}  	} -	// directory did not exist. +	/* directory did not exist. */  	return NULL;  } -static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const char *path,char **name,int symDepth) +static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relDir, +					       const YCHAR *path, +					       YCHAR **name, +					       int symDepth, +					       int *notDir, int *loop)  { -	return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth); +	return yaffsfs_DoFindDirectory(relDir, path, name, symDepth, notDir, +						loop);  } -// yaffsfs_FindObject turns a path for an existing object into the object -// -static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path,int symDepth) +/* + * yaffsfs_FindObject turns a path for an existing object into the object + */ +static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relDir, +					    const YCHAR *path, int symDepth, +					    int getEquiv, +					    struct yaffs_obj **dirOut, +					    int *notDir, int *loop)  { -	yaffs_Object *dir; -	char *name; +	struct yaffs_obj *dir; +	struct yaffs_obj *obj; +	YCHAR *name; + +	dir = +	    yaffsfs_FindDirectory(relDir, path, &name, symDepth, notDir, loop); + +	if (dirOut) +		*dirOut = dir; + +	if (dir && *name) +		obj = yaffs_find_by_name(dir, name); +	else +		obj = dir; -	dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth); +	if (getEquiv) +		obj = yaffs_get_equivalent_obj(obj); -	if(dir && *name) -	{ -		return yaffs_FindObjectByName(dir,name); +	return obj; +} + +/************************************************************************* + *	Start of yaffsfs visible functions. + *************************************************************************/ + +int yaffs_dup(int handle) +{ +	int newHandleNumber = -1; +	struct yaffsfs_FileDes *existingFD = NULL; +	struct yaffsfs_Handle *existingHandle = NULL; +	struct yaffsfs_Handle *newHandle = NULL; + +	yaffsfs_Lock(); +	existingHandle = yaffsfs_HandleToPointer(handle); +	existingFD = yaffsfs_HandleToFileDes(handle); +	if (existingFD) +		newHandleNumber = yaffsfs_NewHandle(&newHandle); +	if (newHandle) { +		newHandle->fdId = existingHandle->fdId; +		existingFD->handleCount++;  	} -	return dir; +	yaffsfs_Unlock(); + +	if (!existingFD) +		yaffsfs_SetError(-EBADF); +	else if (!newHandle) +		yaffsfs_SetError(-ENOMEM); + +	return newHandleNumber; +  } +static int yaffsfs_TooManyObjects(struct yaffs_dev *dev) +{ +	int current_objects = dev->n_obj - dev->n_deleted_files; +	if (dev->param.max_objects && current_objects > dev->param.max_objects) +		return 1; +	else +		return 0; +} -int yaffs_open(const char *path, int oflag, int mode) +int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)  { -	yaffs_Object *obj = NULL; -	yaffs_Object *dir = NULL; -	char *name; +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	YCHAR *name;  	int handle = -1; -	yaffsfs_Handle *h = NULL; -	int alreadyOpen = 0; -	int alreadyExclusive = 0; +	struct yaffsfs_FileDes *fd = NULL;  	int openDenied = 0;  	int symDepth = 0;  	int errorReported = 0; +	int rwflags = oflag & (O_RDWR | O_RDONLY | O_WRONLY); +	u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0; +	u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0; +	u8 sharedReadAllowed; +	u8 sharedWriteAllowed; +	u8 alreadyReading; +	u8 alreadyWriting; +	u8 readRequested; +	u8 writeRequested; +	int notDir = 0; +	int loop = 0; -	int i; +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} -	// todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR +	/* O_EXCL only has meaning if O_CREAT is specified */ +	if (!(oflag & O_CREAT)) +		oflag &= ~(O_EXCL); +	/* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */ +	if ((oflag & O_CREAT) & (oflag & O_EXCL)) +		oflag &= ~(O_TRUNC); -	yaffsfs_Lock(); +	/* Todo: Are there any more flag combos to sanitise ? */ -	handle = yaffsfs_GetHandle(); +	/* Figure out if reading or writing is requested */ -	if(handle >= 0) -	{ +	readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0; +	writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0; -		h = yaffsfs_GetHandlePointer(handle); +	yaffsfs_Lock(); +	handle = yaffsfs_NewHandleAndFileDes(); -		// try to find the exisiting object -		obj = yaffsfs_FindObject(NULL,path,0); +	if (handle < 0) { +		yaffsfs_SetError(-ENFILE); +		errorReported = 1; +	} else { -		if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) -		{ +		fd = yaffsfs_HandleToFileDes(handle); -			obj = yaffsfs_FollowLink(obj,symDepth++); -		} +		/* try to find the exisiting object */ +		obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL); -		if(obj) -		{ -			// Check if the object is already in use -			alreadyOpen = alreadyExclusive = 0; +		obj = yaffsfs_FollowLink(obj, symDepth++, &loop); -			for(i = 0; i <= YAFFSFS_N_HANDLES; i++) -			{ +		if (obj && +		    obj->variant_type != YAFFS_OBJECT_TYPE_FILE && +		    obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) +			obj = NULL; -				if(i != handle && -				   yaffsfs_handle[i].inUse && -				    obj == yaffsfs_handle[i].obj) -				 { -				 	alreadyOpen = 1; -					if(yaffsfs_handle[i].exclusive) -					{ -						alreadyExclusive = 1; -					} -				 } -			} +		if (obj) { + +			/* The file already exists or it might be a directory */ -			if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive) -			{ +			/* A directory can't be opened as a file */ +			if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {  				openDenied = 1; +				yaffsfs_SetError(-EISDIR); +				errorReported = 1;  			} -			// Open should fail if O_CREAT and O_EXCL are specified -			if((oflag & O_EXCL) && (oflag & O_CREAT)) -			{ +			/* Open should fail if O_CREAT and O_EXCL are specified +			 * for a file that exists. +			 */ +			if (!errorReported && +			    (oflag & O_EXCL) && (oflag & O_CREAT)) {  				openDenied = 1;  				yaffsfs_SetError(-EEXIST);  				errorReported = 1;  			} -			// Check file permissions -			if( (oflag & (O_RDWR | O_WRONLY)) == 0 &&     // ie O_RDONLY -			   !(obj->yst_mode & S_IREAD)) -			{ +			/* Check file permissions */ +			if (readRequested && !(obj->yst_mode & S_IREAD))  				openDenied = 1; -			} -			if( (oflag & O_RDWR) && -			   !(obj->yst_mode & S_IREAD)) -			{ +			if (writeRequested && !(obj->yst_mode & S_IWRITE))  				openDenied = 1; -			} -			if( (oflag & (O_RDWR | O_WRONLY)) && -			   !(obj->yst_mode & S_IWRITE)) -			{ +			if (!errorReported && writeRequested && +			    obj->my_dev->read_only) {  				openDenied = 1; +				yaffsfs_SetError(-EROFS); +				errorReported = 1;  			} -		} +			if (openDenied && !errorReported) { +				yaffsfs_SetError(-EACCES); +				errorReported = 1; +			} + +			/* Check sharing of an existing object. */ +			if (!openDenied) { +				struct yaffsfs_FileDes *fdx; +				int i; + +				sharedReadAllowed = 1; +				sharedWriteAllowed = 1; +				alreadyReading = 0; +				alreadyWriting = 0; +				for (i = 0; i < YAFFSFS_N_HANDLES; i++) { +					fdx = &yaffsfs_fd[i]; +					if (fdx->handleCount > 0 && +					    fdx->inodeId >= 0 && +					    yaffsfs_inode[fdx->inodeId].iObj +					    == obj) { +						if (!fdx->shareRead) +							sharedReadAllowed = 0; +						if (!fdx->shareWrite) +							sharedWriteAllowed = 0; +						if (fdx->reading) +							alreadyReading = 1; +						if (fdx->writing) +							alreadyWriting = 1; +					} +				} -		else if((oflag & O_CREAT)) -		{ -			// Let's see if we can create this file -			dir = yaffsfs_FindDirectory(NULL,path,&name,0); -			if(dir) -			{ -				obj = yaffs_MknodFile(dir,name,mode,0,0); +				if ((!sharedReadAllowed && readRequested) || +				    (!shareRead && alreadyReading) || +				    (!sharedWriteAllowed && writeRequested) || +				    (!shareWrite && alreadyWriting)) { +					openDenied = 1; +					yaffsfs_SetError(-EBUSY); +					errorReported = 1; +				}  			} -			else -			{ + +		} + +		/* If we could not open an existing object, then let's see if +		 * the directory exists. If not, error. +		 */ +		if (!obj && !errorReported) { +			dir = yaffsfs_FindDirectory(NULL, path, &name, 0, +						    ¬Dir, &loop); +			if (!dir && notDir) {  				yaffsfs_SetError(-ENOTDIR); +				errorReported = 1; +			} else if (loop) { +				yaffsfs_SetError(-ELOOP); +				errorReported = 1; +			} else if (!dir) { +				yaffsfs_SetError(-ENOENT); +				errorReported = 1;  			}  		} -		if(obj && !openDenied) -		{ -			h->obj = obj; -			h->inUse = 1; -	    	h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1; -			h->append =  (oflag & O_APPEND) ? 1 : 0; -			h->exclusive = (oflag & O_EXCL) ? 1 : 0; -			h->position = 0; +		if (!obj && dir && !errorReported && (oflag & O_CREAT)) { +			/* Let's see if we can create this file */ +			if (dir->my_dev->read_only) { +				yaffsfs_SetError(-EROFS); +				errorReported = 1; +			} else if (yaffsfs_TooManyObjects(dir->my_dev)) { +				yaffsfs_SetError(-ENFILE); +				errorReported = 1; +			} else +				obj = yaffs_create_file(dir, name, mode, 0, 0); -			obj->inUse++; -			if((oflag & O_TRUNC) && !h->readOnly) -			{ -				//todo truncate -				yaffs_ResizeFile(obj,0); +			if (!obj && !errorReported) { +				yaffsfs_SetError(-ENOSPC); +				errorReported = 1;  			} +		} +		if (!obj && dir && !errorReported && !(oflag & O_CREAT)) { +			yaffsfs_SetError(-ENOENT); +			errorReported = 1;  		} -		else -		{ -			yaffsfs_PutHandle(handle); -			if(!errorReported) -			{ -				yaffsfs_SetError(-EACCESS); -				errorReported = 1; + +		if (obj && !openDenied) { +			int inodeId = yaffsfs_GetInodeIdForObject(obj); + +			if (inodeId < 0) { +				/* +				 * Todo: Fix any problem if inodes run out, +				 * That can't happen if the number of inode +				 * items >= number of handles. +				 */  			} + +			fd->inodeId = inodeId; +			fd->reading = readRequested; +			fd->writing = writeRequested; +			fd->append = (oflag & O_APPEND) ? 1 : 0; +			fd->position = 0; +			fd->shareRead = shareRead; +			fd->shareWrite = shareWrite; + +			/* Hook inode to object */ +			obj->my_inode = (void *)&yaffsfs_inode[inodeId]; + +			if ((oflag & O_TRUNC) && fd->writing) +				yaffs_resize_file(obj, 0); +		} else { +			yaffsfs_PutHandle(handle); +			if (!errorReported) +				yaffsfs_SetError(0);	/* Problem */  			handle = -1;  		} -  	}  	yaffsfs_Unlock(); @@ -484,32 +994,68 @@ int yaffs_open(const char *path, int oflag, int mode)  	return handle;  } -int yaffs_close(int fd) +int yaffs_open(const YCHAR *path, int oflag, int mode)  { -	yaffsfs_Handle *h = NULL; -	int retVal = 0; +	return yaffs_open_sharing(path, oflag, mode, +				  YAFFS_SHARE_READ | YAFFS_SHARE_WRITE); +} + +int yaffs_Dofsync(int handle, int datasync) +{ +	int retVal = -1; +	struct yaffs_obj *obj;  	yaffsfs_Lock(); -	h = yaffsfs_GetHandlePointer(fd); +	obj = yaffsfs_HandleToObject(handle); -	if(h && h->inUse) -	{ -		// clean up -		yaffs_FlushFile(h->obj,1); -		h->obj->inUse--; -		if(h->obj->inUse <= 0 && h->obj->unlinked) -		{ -			yaffs_DeleteFile(h->obj); -		} -		yaffsfs_PutHandle(fd); +	if (!obj) +		yaffsfs_SetError(-EBADF); +	else if (obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else { +		yaffs_flush_file(obj, 1, datasync);  		retVal = 0;  	} -	else -	{ -		// bad handle + +	yaffsfs_Unlock(); + +	return retVal; +} + +int yaffs_fsync(int handle) +{ +	return yaffs_Dofsync(handle, 0); +} + +int yaffs_flush(int handle) +{ +	return yaffs_fsync(handle); +} + +int yaffs_fdatasync(int handle) +{ +	return yaffs_Dofsync(handle, 1); +} + +int yaffs_close(int handle) +{ +	struct yaffsfs_Handle *h = NULL; +	struct yaffs_obj *obj = NULL; +	int retVal = -1; + +	yaffsfs_Lock(); + +	h = yaffsfs_HandleToPointer(handle); +	obj = yaffsfs_HandleToObject(handle); + +	if (!h || !obj)  		yaffsfs_SetError(-EBADF); -		retVal = -1; +	else { +		/* clean up */ +		yaffs_flush_file(obj, 1, 0); +		yaffsfs_PutHandle(handle); +		retVal = 0;  	}  	yaffsfs_Unlock(); @@ -517,378 +1063,774 @@ int yaffs_close(int fd)  	return retVal;  } -int yaffs_read(int fd, void *buf, unsigned int nbyte) +int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte, +		    int isPread, loff_t offset)  { -	yaffsfs_Handle *h = NULL; -	yaffs_Object *obj = NULL; -	int pos = 0; -	int nRead = -1; -	int maxRead; +	struct yaffsfs_FileDes *fd = NULL; +	struct yaffs_obj *obj = NULL; +	loff_t pos = 0; +	loff_t startPos = 0; +	loff_t endPos = 0; +	int nRead = 0; +	int nToRead = 0; +	int totalRead = 0; +	loff_t maxRead; +	u8 *buf = (u8 *) vbuf; + +	if (!vbuf) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	}  	yaffsfs_Lock(); -	h = yaffsfs_GetHandlePointer(fd); -	obj = yaffsfs_GetHandleObject(fd); +	fd = yaffsfs_HandleToFileDes(handle); +	obj = yaffsfs_HandleToObject(handle); -	if(!h || !obj) -	{ -		// bad handle +	if (!fd || !obj) { +		/* bad handle */  		yaffsfs_SetError(-EBADF); -	} -	else if( h && obj) -	{ -		pos=  h->position; -		if(yaffs_GetObjectFileLength(obj) > pos) -		{ -			maxRead = yaffs_GetObjectFileLength(obj) - pos; -		} +		totalRead = -1; +	} else if (!fd->reading) { +		/* Not a reading handle */ +		yaffsfs_SetError(-EINVAL); +		totalRead = -1; +	} else if (nbyte > YAFFS_MAX_FILE_SIZE) { +		yaffsfs_SetError(-EINVAL); +		totalRead = -1; +	} else { +		if (isPread) +			startPos = offset; +		else +			startPos = fd->position; + +		pos = startPos; + +		if (yaffs_get_obj_length(obj) > pos) +			maxRead = yaffs_get_obj_length(obj) - pos;  		else -		{  			maxRead = 0; -		} -		if(nbyte > maxRead) -		{ +		if (nbyte > maxRead)  			nbyte = maxRead; + +		yaffsfs_GetHandle(handle); + +		endPos = pos + nbyte; + +		if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE || +		    nbyte > YAFFS_MAX_FILE_SIZE || +		    endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) { +			totalRead = -1; +			nbyte = 0;  		} +		while (nbyte > 0) { +			nToRead = YAFFSFS_RW_SIZE - +			    (pos & (YAFFSFS_RW_SIZE - 1)); +			if (nToRead > nbyte) +				nToRead = nbyte; + +			/* Tricky bit... +			 * Need to reverify object in case the device was +			 * unmounted in another thread. +			 */ +			obj = yaffsfs_HandleToObject(handle); +			if (!obj) +				nRead = 0; +			else +				nRead = yaffs_file_rd(obj, buf, pos, nToRead); -		if(nbyte > 0) -		{ -			nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte); -			if(nRead >= 0) -			{ -				h->position = pos + nRead; +			if (nRead > 0) { +				totalRead += nRead; +				pos += nRead; +				buf += nRead;  			} + +			if (nRead == nToRead) +				nbyte -= nRead;  			else -			{ -				//todo error +				nbyte = 0;	/* no more to read */ + +			if (nbyte > 0) { +				yaffsfs_Unlock(); +				yaffsfs_Lock();  			} +  		} -		else -		{ -			nRead = 0; + +		yaffsfs_PutHandle(handle); + +		if (!isPread) { +			if (totalRead >= 0) +				fd->position = startPos + totalRead; +			else +				yaffsfs_SetError(-EINVAL);  		}  	}  	yaffsfs_Unlock(); +	return (totalRead >= 0) ? totalRead : -1; -	return (nRead >= 0) ? nRead : -1; +} +int yaffs_read(int handle, void *buf, unsigned int nbyte) +{ +	return yaffsfs_do_read(handle, buf, nbyte, 0, 0);  } -int yaffs_write(int fd, const void *buf, unsigned int nbyte) +int yaffs_pread(int handle, void *buf, unsigned int nbyte, loff_t offset) +{ +	return yaffsfs_do_read(handle, buf, nbyte, 1, offset); +} + +int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte, +		     int isPwrite, loff_t offset)  { -	yaffsfs_Handle *h = NULL; -	yaffs_Object *obj = NULL; -	int pos = 0; -	int nWritten = -1; -	int writeThrough = 0; +	struct yaffsfs_FileDes *fd = NULL; +	struct yaffs_obj *obj = NULL; +	loff_t pos = 0; +	loff_t startPos = 0; +	loff_t endPos; +	int nWritten = 0; +	int totalWritten = 0; +	int write_trhrough = 0; +	int nToWrite = 0; +	const u8 *buf = (const u8 *)vbuf; + +	if (!vbuf) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	}  	yaffsfs_Lock(); -	h = yaffsfs_GetHandlePointer(fd); -	obj = yaffsfs_GetHandleObject(fd); +	fd = yaffsfs_HandleToFileDes(handle); +	obj = yaffsfs_HandleToObject(handle); -	if(!h || !obj) -	{ -		// bad handle +	if (!fd || !obj) { +		/* bad handle */  		yaffsfs_SetError(-EBADF); -	} -	else if( h && obj && h->readOnly) -	{ -		// todo error -	} -	else if( h && obj) -	{ -		if(h->append) -		{ -			pos =  yaffs_GetObjectFileLength(obj); -		} +		totalWritten = -1; +	} else if (!fd->writing) { +		yaffsfs_SetError(-EINVAL); +		totalWritten = -1; +	} else if (obj->my_dev->read_only) { +		yaffsfs_SetError(-EROFS); +		totalWritten = -1; +	} else { +		if (fd->append) +			startPos = yaffs_get_obj_length(obj); +		else if (isPwrite) +			startPos = offset;  		else -		{ -			pos = h->position; -		} +			startPos = fd->position; -		nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough); +		yaffsfs_GetHandle(handle); +		pos = startPos; +		endPos = pos + nbyte; -		if(nWritten >= 0) -		{ -			h->position = pos + nWritten; +		if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE || +		    nbyte > YAFFS_MAX_FILE_SIZE || +		    endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) { +			totalWritten = -1; +			nbyte = 0;  		} -		else -		{ -			//todo error + +		while (nbyte > 0) { + +			nToWrite = YAFFSFS_RW_SIZE - +			    (pos & (YAFFSFS_RW_SIZE - 1)); +			if (nToWrite > nbyte) +				nToWrite = nbyte; + +			/* Tricky bit... +			 * Need to reverify object in case the device was +			 * remounted or unmounted in another thread. +			 */ +			obj = yaffsfs_HandleToObject(handle); +			if (!obj || obj->my_dev->read_only) +				nWritten = 0; +			else +				nWritten = +				    yaffs_wr_file(obj, buf, pos, nToWrite, +						  write_trhrough); +			if (nWritten > 0) { +				totalWritten += nWritten; +				pos += nWritten; +				buf += nWritten; +			} + +			if (nWritten == nToWrite) +				nbyte -= nToWrite; +			else +				nbyte = 0; + +			if (nWritten < 1 && totalWritten < 1) { +				yaffsfs_SetError(-ENOSPC); +				totalWritten = -1; +			} + +			if (nbyte > 0) { +				yaffsfs_Unlock(); +				yaffsfs_Lock(); +			}  		} +		yaffsfs_PutHandle(handle); + +		if (!isPwrite) { +			if (totalWritten > 0) +				fd->position = startPos + totalWritten; +			else +				yaffsfs_SetError(-EINVAL); +		}  	}  	yaffsfs_Unlock(); +	return (totalWritten >= 0) ? totalWritten : -1; +} + +int yaffs_write(int fd, const void *buf, unsigned int nbyte) +{ +	return yaffsfs_do_write(fd, buf, nbyte, 0, 0); +} + +int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, loff_t offset) +{ +	return yaffsfs_do_write(fd, buf, nbyte, 1, offset); +} + +int yaffs_truncate(const YCHAR *path, loff_t new_size) +{ +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	int result = YAFFS_FAIL; +	int notDir = 0; +	int loop = 0; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); +	obj = yaffsfs_FollowLink(obj, 0, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj) +		yaffsfs_SetError(-ENOENT); +	else if (obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) +		yaffsfs_SetError(-EISDIR); +	else if (obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE) +		yaffsfs_SetError(-EINVAL); +	else +		result = yaffs_resize_file(obj, new_size); -	return (nWritten >= 0) ? nWritten : -1; +	yaffsfs_Unlock(); +	return (result) ? 0 : -1;  } -int yaffs_truncate(int fd, off_t newSize) +int yaffs_ftruncate(int handle, loff_t new_size)  { -	yaffsfs_Handle *h = NULL; -	yaffs_Object *obj = NULL; +	struct yaffsfs_FileDes *fd = NULL; +	struct yaffs_obj *obj = NULL;  	int result = 0;  	yaffsfs_Lock(); -	h = yaffsfs_GetHandlePointer(fd); -	obj = yaffsfs_GetHandleObject(fd); +	fd = yaffsfs_HandleToFileDes(handle); +	obj = yaffsfs_HandleToObject(handle); -	if(!h || !obj) -	{ -		// bad handle +	if (!fd || !obj) +		/* bad handle */  		yaffsfs_SetError(-EBADF); -	} +	else if (!fd->writing) +		yaffsfs_SetError(-EINVAL); +	else if (obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE) +		yaffsfs_SetError(-EINVAL);  	else -	{ -		// resize the file -		result = yaffs_ResizeFile(obj,newSize); -	} +		/* resize the file */ +		result = yaffs_resize_file(obj, new_size);  	yaffsfs_Unlock(); -  	return (result) ? 0 : -1;  } -off_t yaffs_lseek(int fd, off_t offset, int whence) +loff_t yaffs_lseek(int handle, loff_t offset, int whence)  { -	yaffsfs_Handle *h = NULL; -	yaffs_Object *obj = NULL; -	int pos = -1; -	int fSize = -1; +	struct yaffsfs_FileDes *fd = NULL; +	struct yaffs_obj *obj = NULL; +	loff_t pos = -1; +	loff_t fSize = -1;  	yaffsfs_Lock(); -	h = yaffsfs_GetHandlePointer(fd); -	obj = yaffsfs_GetHandleObject(fd); +	fd = yaffsfs_HandleToFileDes(handle); +	obj = yaffsfs_HandleToObject(handle); -	if(!h || !obj) -	{ -		// bad handle +	if (!fd || !obj)  		yaffsfs_SetError(-EBADF); -	} -	else if(whence == SEEK_SET) -	{ -		if(offset >= 0) -		{ -			pos = offset; -		} -	} -	else if(whence == SEEK_CUR) -	{ -		if( (h->position + offset) >= 0) -		{ -			pos = (h->position + offset); -		} -	} -	else if(whence == SEEK_END) -	{ -		fSize = yaffs_GetObjectFileLength(obj); -		if(fSize >= 0 && (fSize + offset) >= 0) -		{ -			pos = fSize + offset; +	else if (offset > YAFFS_MAX_FILE_SIZE) +		yaffsfs_SetError(-EINVAL); +	else { +		if (whence == SEEK_SET) { +			if (offset >= 0) +				pos = offset; +		} else if (whence == SEEK_CUR) { +			if ((fd->position + offset) >= 0) +				pos = (fd->position + offset); +		} else if (whence == SEEK_END) { +			fSize = yaffs_get_obj_length(obj); +			if (fSize >= 0 && (fSize + offset) >= 0) +				pos = fSize + offset;  		} -	} -	if(pos >= 0) -	{ -		h->position = pos; -	} -	else -	{ -		// todo error +		if (pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE) +			fd->position = pos; +		else { +			yaffsfs_SetError(-EINVAL); +			pos = -1; +		}  	} -  	yaffsfs_Unlock();  	return pos;  } - -int yaffsfs_DoUnlink(const char *path,int isDirectory) +int yaffsfs_DoUnlink(const YCHAR *path, int isDirectory)  { -	yaffs_Object *dir = NULL; -	yaffs_Object *obj = NULL; -	char *name; +	struct yaffs_obj *dir = NULL; +	struct yaffs_obj *obj = NULL; +	YCHAR *name;  	int result = YAFFS_FAIL; +	int notDir = 0; +	int loop = 0; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	}  	yaffsfs_Lock(); -	obj = yaffsfs_FindObject(NULL,path,0); -	dir = yaffsfs_FindDirectory(NULL,path,&name,0); -	if(!dir) -	{ +	obj = yaffsfs_FindObject(NULL, path, 0, 0, NULL, NULL, NULL); +	dir = yaffsfs_FindDirectory(NULL, path, &name, 0, ¬Dir, &loop); + +	if (!dir && notDir)  		yaffsfs_SetError(-ENOTDIR); -	} -	else if(!obj) -	{ +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir)  		yaffsfs_SetError(-ENOENT); -	} -	else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) -	{ +	else if (yaffs_strncmp(name, _Y("."), 2) == 0) +		yaffsfs_SetError(-EINVAL); +	else if (!obj) +		yaffsfs_SetError(-ENOENT); +	else if (obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else if (!isDirectory && +		 obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)  		yaffsfs_SetError(-EISDIR); -	} -	else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) -	{ +	else if (isDirectory && +		 obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)  		yaffsfs_SetError(-ENOTDIR); -	} -	else -	{ -		result = yaffs_Unlink(dir,name); +	else if (isDirectory && obj == obj->my_dev->root_dir) +		yaffsfs_SetError(-EBUSY);	/* Can't rmdir a root */ +	else { +		result = yaffs_unlinker(dir, name); -		if(result == YAFFS_FAIL && isDirectory) -		{ +		if (result == YAFFS_FAIL && isDirectory)  			yaffsfs_SetError(-ENOTEMPTY); -		}  	}  	yaffsfs_Unlock(); -	// todo error -  	return (result == YAFFS_FAIL) ? -1 : 0;  } -int yaffs_rmdir(const char *path) -{ -	return yaffsfs_DoUnlink(path,1); -} -int yaffs_unlink(const char *path) +int yaffs_unlink(const YCHAR *path)  { -	return yaffsfs_DoUnlink(path,0); +	return yaffsfs_DoUnlink(path, 0);  } -int yaffs_rename(const char *oldPath, const char *newPath) +int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)  { -	yaffs_Object *olddir = NULL; -	yaffs_Object *newdir = NULL; -	yaffs_Object *obj = NULL; -	char *oldname; -	char *newname; -	int result= YAFFS_FAIL; -	int renameAllowed = 1; +	struct yaffs_obj *olddir = NULL; +	struct yaffs_obj *newdir = NULL; +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *newobj = NULL; +	YCHAR *oldname; +	YCHAR *newname; +	int result = YAFFS_FAIL; +	int rename_allowed = 1; +	int notOldDir = 0; +	int notNewDir = 0; +	int oldLoop = 0; +	int newLoop = 0; -	yaffsfs_Lock(); +	YCHAR *alt_newpath = NULL; + +	if (!oldPath || !newPath) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} -	olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0); -	newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0); -	obj = yaffsfs_FindObject(NULL,oldPath,0); +	if (yaffsfs_CheckPath(oldPath) < 0 || yaffsfs_CheckPath(newPath) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} -	if(!olddir || !newdir || !obj) -	{ -		// bad file -		yaffsfs_SetError(-EBADF); -		renameAllowed = 0; +	if (yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0) { +		yaffsfs_SetError(-ENOMEM); +		return -1;  	} -	else if(olddir->myDev != newdir->myDev) -	{ -		// oops must be on same device -		// todo error +	if (alt_newpath) +		newPath = alt_newpath; + +	yaffsfs_Lock(); + +	olddir = yaffsfs_FindDirectory(NULL, oldPath, &oldname, 0, +				       ¬OldDir, &oldLoop); +	newdir = yaffsfs_FindDirectory(NULL, newPath, &newname, 0, +				       ¬NewDir, &newLoop); +	obj = yaffsfs_FindObject(NULL, oldPath, 0, 0, NULL, NULL, NULL); +	newobj = yaffsfs_FindObject(NULL, newPath, 0, 0, NULL, NULL, NULL); + +	/* If the object being renamed is a directory and the +	 * path ended with a "/" then the olddir == obj. +	 * We pass through NULL for the old name to tell the lower layers +	 * to use olddir as the object. +	 */ + +	if (olddir == obj) +		oldname = NULL; + +	if ((!olddir && notOldDir) || (!newdir && notNewDir)) { +		yaffsfs_SetError(-ENOTDIR); +		rename_allowed = 0; +	} else if (oldLoop || newLoop) { +		yaffsfs_SetError(-ELOOP); +		rename_allowed = 0; +	} else if (olddir && oldname && +			yaffs_strncmp(oldname, _Y("."), 2) == 0) { +		yaffsfs_SetError(-EINVAL); +		rename_allowed = 0; +	} else if (!olddir || !newdir || !obj) { +		yaffsfs_SetError(-ENOENT); +		rename_allowed = 0; +	} else if (obj->my_dev->read_only) { +		yaffsfs_SetError(-EROFS); +		rename_allowed = 0; +	} else if (yaffs_is_non_empty_dir(newobj)) { +		yaffsfs_SetError(-ENOTEMPTY); +		rename_allowed = 0; +	} else if (olddir->my_dev != newdir->my_dev) { +		/* Rename must be on same device */  		yaffsfs_SetError(-EXDEV); -		renameAllowed = 0; -	} -	else if(obj && obj->variantType == 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 +		rename_allowed = 0; +	} else if (obj && obj->variant_type == 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; +		struct yaffs_obj *xx = newdir; -		while( renameAllowed && xx) -		{ -			if(xx == obj) -			{ -				renameAllowed = 0; -			} +		while (rename_allowed && xx) { +			if (xx == obj) +				rename_allowed = 0;  			xx = xx->parent;  		} -		if(!renameAllowed) yaffsfs_SetError(-EACCESS); +		if (!rename_allowed) +			yaffsfs_SetError(-EINVAL);  	} -	if(renameAllowed) -	{ -		result = yaffs_RenameObject(olddir,oldname,newdir,newname); -	} +	if (rename_allowed) +		result = yaffs_rename_obj(olddir, oldname, newdir, newname);  	yaffsfs_Unlock(); +	kfree(alt_newpath); +  	return (result == YAFFS_FAIL) ? -1 : 0;  } - -static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf) +static int yaffsfs_DoStat(struct yaffs_obj *obj, struct yaffs_stat *buf)  {  	int retVal = -1; -	if(obj) -	{ -		obj = yaffs_GetEquivalentObject(obj); -	} +	obj = yaffs_get_equivalent_obj(obj); -	if(obj && buf) -	{ -    	buf->st_dev = (int)obj->myDev->genericDevice; -    	buf->st_ino = obj->objectId; -    	buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits +	if (obj && buf) { +		buf->st_dev = (int)obj->my_dev->os_context; +		buf->st_ino = obj->obj_id; +		buf->st_mode = obj->yst_mode & ~S_IFMT; -		if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) -		{ +		if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)  			buf->st_mode |= S_IFDIR; -		} -		else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) -		{ +		else if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)  			buf->st_mode |= S_IFLNK; -		} -		else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) -		{ +		else if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)  			buf->st_mode |= S_IFREG; -		} -    	buf->st_nlink = yaffs_GetObjectLinkCount(obj); -    	buf->st_uid = 0; -    	buf->st_gid = 0;; -    	buf->st_rdev = obj->yst_rdev; -    	buf->st_size = yaffs_GetObjectFileLength(obj); -		buf->st_blksize = obj->myDev->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; +		buf->st_nlink = yaffs_get_obj_link_count(obj); +		buf->st_uid = 0; +		buf->st_gid = 0; +		buf->st_rdev = obj->yst_rdev; +		buf->st_size = yaffs_get_obj_length(obj); +		buf->st_blksize = obj->my_dev->data_bytes_per_chunk; +		buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / +		    buf->st_blksize; +#if CONFIG_YAFFS_WINCE +		buf->yst_wince_atime[0] = obj->win_atime[0]; +		buf->yst_wince_atime[1] = obj->win_atime[1]; +		buf->yst_wince_ctime[0] = obj->win_ctime[0]; +		buf->yst_wince_ctime[1] = obj->win_ctime[1]; +		buf->yst_wince_mtime[0] = obj->win_mtime[0]; +		buf->yst_wince_mtime[1] = obj->win_mtime[1]; +#else +		buf->yst_atime = obj->yst_atime; +		buf->yst_ctime = obj->yst_ctime; +		buf->yst_mtime = obj->yst_mtime; +#endif  		retVal = 0;  	}  	return retVal;  } -static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int doLStat) +static int yaffsfs_DoStatOrLStat(const YCHAR *path, +				 struct yaffs_stat *buf, int doLStat)  { -	yaffs_Object *obj; +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	int retVal = -1; +	int notDir = 0; +	int loop = 0; + +	if (!path || !buf) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + +	if (!doLStat && obj) +		obj = yaffsfs_FollowLink(obj, 0, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj) +		yaffsfs_SetError(-ENOENT); +	else +		retVal = yaffsfs_DoStat(obj, buf); + +	yaffsfs_Unlock(); + +	return retVal; + +} + +int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) +{ +	return yaffsfs_DoStatOrLStat(path, buf, 0); +} + +int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) +{ +	return yaffsfs_DoStatOrLStat(path, buf, 1); +} + +int yaffs_fstat(int fd, struct yaffs_stat *buf) +{ +	struct yaffs_obj *obj;  	int retVal = -1; +	if (!buf) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} +  	yaffsfs_Lock(); -	obj = yaffsfs_FindObject(NULL,path,0); +	obj = yaffsfs_HandleToObject(fd); + +	if (obj) +		retVal = yaffsfs_DoStat(obj, buf); +	else +		/* bad handle */ +		yaffsfs_SetError(-EBADF); + +	yaffsfs_Unlock(); + +	return retVal; +} -	if(!doLStat && obj) -	{ -		obj = yaffsfs_FollowLink(obj,0); +static int yaffsfs_DoUtime(struct yaffs_obj *obj, +			   const struct yaffs_utimbuf *buf) +{ +	int retVal = -1; +	int result; + +	struct yaffs_utimbuf local; + +	obj = yaffs_get_equivalent_obj(obj); + +	if (obj && obj->my_dev->read_only) { +		yaffsfs_SetError(-EROFS); +		return -1; +	} + +	if (!buf) { +		local.actime = Y_CURRENT_TIME; +		local.modtime = local.actime; +		buf = &local; +	} + +	if (obj) { +		obj->yst_atime = buf->actime; +		obj->yst_mtime = buf->modtime; +		obj->dirty = 1; +		result = yaffs_flush_file(obj, 0, 0); +		retVal = result == YAFFS_OK ? 0 : -1; +	} + +	return retVal; +} + +int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf) +{ +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	int retVal = -1; +	int notDir = 0; +	int loop = 0; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1;  	} -	if(obj) -	{ -		retVal = yaffsfs_DoStat(obj,buf); +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1;  	} + +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj) +		yaffsfs_SetError(-ENOENT);  	else -	{ -		// todo error not found +		retVal = yaffsfs_DoUtime(obj, buf); + +	yaffsfs_Unlock(); + +	return retVal; + +} + +int yaffs_futime(int fd, const struct yaffs_utimbuf *buf) +{ +	struct yaffs_obj *obj; + +	int retVal = -1; + +	yaffsfs_Lock(); +	obj = yaffsfs_HandleToObject(fd); + +	if (obj) +		retVal = yaffsfs_DoUtime(obj, buf); +	else +		/* bad handle */ +		yaffsfs_SetError(-EBADF); + +	yaffsfs_Unlock(); + +	return retVal; +} + +#ifndef CONFIG_YAFFS_WINCE +/* xattrib functions */ + +static int yaffs_do_setxattr(const YCHAR *path, const char *name, +			     const void *data, int size, int flags, int follow) +{ +	struct yaffs_obj *obj; +	struct yaffs_obj *dir; +	int notDir = 0; +	int loop = 0; + +	int retVal = -1; + +	if (!path || !name || !data) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + +	if (follow) +		obj = yaffsfs_FollowLink(obj, 0, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj)  		yaffsfs_SetError(-ENOENT); +	else { +		retVal = yaffs_set_xattrib(obj, name, data, size, flags); +		if (retVal < 0) { +			yaffsfs_SetError(retVal); +			retVal = -1; +		}  	}  	yaffsfs_Unlock(); @@ -897,33 +1839,41 @@ static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int do  } -int yaffs_stat(const char *path, struct yaffs_stat *buf) +int yaffs_setxattr(const YCHAR *path, const char *name, +		   const void *data, int size, int flags)  { -	return yaffsfs_DoStatOrLStat(path,buf,0); +	return yaffs_do_setxattr(path, name, data, size, flags, 1);  } -int yaffs_lstat(const char *path, struct yaffs_stat *buf) +int yaffs_lsetxattr(const YCHAR *path, const char *name, +		    const void *data, int size, int flags)  { -	return yaffsfs_DoStatOrLStat(path,buf,1); +	return yaffs_do_setxattr(path, name, data, size, flags, 0);  } -int yaffs_fstat(int fd, struct yaffs_stat *buf) +int yaffs_fsetxattr(int fd, const char *name, +		    const void *data, int size, int flags)  { -	yaffs_Object *obj; +	struct yaffs_obj *obj;  	int retVal = -1; +	if (!name || !data) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} +  	yaffsfs_Lock(); -	obj = yaffsfs_GetHandleObject(fd); +	obj = yaffsfs_HandleToObject(fd); -	if(obj) -	{ -		retVal = yaffsfs_DoStat(obj,buf); -	} -	else -	{ -		// bad handle +	if (!obj)  		yaffsfs_SetError(-EBADF); +	else { +		retVal = yaffs_set_xattrib(obj, name, data, size, flags); +		if (retVal < 0) { +			yaffsfs_SetError(retVal); +			retVal = -1; +		}  	}  	yaffsfs_Unlock(); @@ -931,43 +1881,128 @@ int yaffs_fstat(int fd, struct yaffs_stat *buf)  	return retVal;  } -static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode) +static int yaffs_do_getxattr(const YCHAR *path, const char *name, +			     void *data, int size, int follow)  { -	int result = YAFFS_FAIL; +	struct yaffs_obj *obj; +	struct yaffs_obj *dir; +	int retVal = -1; +	int notDir = 0; +	int loop = 0; -	if(obj) -	{ -		obj = yaffs_GetEquivalentObject(obj); +	if (!path || !name || !data) { +		yaffsfs_SetError(-EFAULT); +		return -1;  	} -	if(obj) -	{ -		obj->yst_mode = mode; -		obj->dirty = 1; -		result = yaffs_FlushFile(obj,0); +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1;  	} -	return result == YAFFS_OK ? 0 : -1; +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + +	if (follow) +		obj = yaffsfs_FollowLink(obj, 0, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj) +		yaffsfs_SetError(-ENOENT); +	else { +		retVal = yaffs_get_xattrib(obj, name, data, size); +		if (retVal < 0) { +			yaffsfs_SetError(retVal); +			retVal = -1; +		} +	} +	yaffsfs_Unlock(); + +	return retVal; + +} + +int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size) +{ +	return yaffs_do_getxattr(path, name, data, size, 1);  } +int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size) +{ +	return yaffs_do_getxattr(path, name, data, size, 0); +} -int yaffs_chmod(const char *path, mode_t mode) +int yaffs_fgetxattr(int fd, const char *name, void *data, int size)  { -	yaffs_Object *obj; +	struct yaffs_obj *obj;  	int retVal = -1; +	if (!name || !data) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} +  	yaffsfs_Lock(); -	obj = yaffsfs_FindObject(NULL,path,0); +	obj = yaffsfs_HandleToObject(fd); + +	if (obj) { +		retVal = yaffs_get_xattrib(obj, name, data, size); +		if (retVal < 0) { +			yaffsfs_SetError(retVal); +			retVal = -1; +		} +	} else +		/* bad handle */ +		yaffsfs_SetError(-EBADF); -	if(obj) -	{ -		retVal = yaffsfs_DoChMod(obj,mode); +	yaffsfs_Unlock(); + +	return retVal; +} + +static int yaffs_do_listxattr(const YCHAR *path, char *data, +			      int size, int follow) +{ +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	int retVal = -1; +	int notDir = 0; +	int loop = 0; + +	if (!path || !data) { +		yaffsfs_SetError(-EFAULT); +		return -1;  	} -	else -	{ -		// todo error not found + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + +	if (follow) +		obj = yaffsfs_FollowLink(obj, 0, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj)  		yaffsfs_SetError(-ENOENT); +	else { +		retVal = yaffs_list_xattrib(obj, data, size); +		if (retVal < 0) { +			yaffsfs_SetError(retVal); +			retVal = -1; +		}  	}  	yaffsfs_Unlock(); @@ -976,317 +2011,906 @@ int yaffs_chmod(const char *path, mode_t mode)  } +int yaffs_listxattr(const YCHAR *path, char *data, int size) +{ +	return yaffs_do_listxattr(path, data, size, 1); +} -int yaffs_fchmod(int fd, mode_t mode) +int yaffs_llistxattr(const YCHAR *path, char *data, int size) +{ +	return yaffs_do_listxattr(path, data, size, 0); +} + +int yaffs_flistxattr(int fd, char *data, int size)  { -	yaffs_Object *obj; +	struct yaffs_obj *obj;  	int retVal = -1; +	if (!data) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} +  	yaffsfs_Lock(); -	obj = yaffsfs_GetHandleObject(fd); +	obj = yaffsfs_HandleToObject(fd); -	if(obj) -	{ -		retVal = yaffsfs_DoChMod(obj,mode); -	} -	else -	{ -		// bad handle +	if (obj) { +		retVal = yaffs_list_xattrib(obj, data, size); +		if (retVal < 0) { +			yaffsfs_SetError(retVal); +			retVal = -1; +		} +	} else +		/* bad handle */  		yaffsfs_SetError(-EBADF); + +	yaffsfs_Unlock(); + +	return retVal; +} + +static int yaffs_do_removexattr(const YCHAR *path, const char *name, +				int follow) +{ +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	int notDir = 0; +	int loop = 0; +	int retVal = -1; + +	if (!path || !name) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + +	if (follow) +		obj = yaffsfs_FollowLink(obj, 0, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj) +		yaffsfs_SetError(-ENOENT); +	else { +		retVal = yaffs_remove_xattrib(obj, name); +		if (retVal < 0) { +			yaffsfs_SetError(retVal); +			retVal = -1; +		}  	}  	yaffsfs_Unlock();  	return retVal; + +} + +int yaffs_removexattr(const YCHAR *path, const char *name) +{ +	return yaffs_do_removexattr(path, name, 1);  } +int yaffs_lremovexattr(const YCHAR *path, const char *name) +{ +	return yaffs_do_removexattr(path, name, 0); +} -int yaffs_mkdir(const char *path, mode_t mode) +int yaffs_fremovexattr(int fd, const char *name)  { -	yaffs_Object *parent = NULL; -	yaffs_Object *dir = NULL; -	char *name; -	int retVal= -1; +	struct yaffs_obj *obj; + +	int retVal = -1; + +	if (!name) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	}  	yaffsfs_Lock(); -	parent = yaffsfs_FindDirectory(NULL,path,&name,0); -	if(parent) -		dir = yaffs_MknodDirectory(parent,name,mode,0,0); -	if(dir) -	{ +	obj = yaffsfs_HandleToObject(fd); + +	if (obj) { +		retVal = yaffs_remove_xattrib(obj, name); +		if (retVal < 0) { +			yaffsfs_SetError(retVal); +			retVal = -1; +		} +	} else +		/* bad handle */ +		yaffsfs_SetError(-EBADF); + +	yaffsfs_Unlock(); + +	return retVal; +} +#endif + +#ifdef CONFIG_YAFFS_WINCE +int yaffs_get_wince_times(int fd, unsigned *wctime, +			  unsigned *watime, unsigned *wmtime) +{ +	struct yaffs_obj *obj; + +	int retVal = -1; + +	yaffsfs_Lock(); +	obj = yaffsfs_HandleToObject(fd); + +	if (obj) { + +		if (wctime) { +			wctime[0] = obj->win_ctime[0]; +			wctime[1] = obj->win_ctime[1]; +		} +		if (watime) { +			watime[0] = obj->win_atime[0]; +			watime[1] = obj->win_atime[1]; +		} +		if (wmtime) { +			wmtime[0] = obj->win_mtime[0]; +			wmtime[1] = obj->win_mtime[1]; +		} + +		retVal = 0; +	} else +		/*  bad handle */ +		yaffsfs_SetError(-EBADF); + +	yaffsfs_Unlock(); + +	return retVal; +} + +int yaffs_set_wince_times(int fd, +			  const unsigned *wctime, +			  const unsigned *watime, const unsigned *wmtime) +{ +	struct yaffs_obj *obj; +	int result; +	int retVal = -1; + +	yaffsfs_Lock(); +	obj = yaffsfs_HandleToObject(fd); + +	if (obj) { + +		if (wctime) { +			obj->win_ctime[0] = wctime[0]; +			obj->win_ctime[1] = wctime[1]; +		} +		if (watime) { +			obj->win_atime[0] = watime[0]; +			obj->win_atime[1] = watime[1]; +		} +		if (wmtime) { +			obj->win_mtime[0] = wmtime[0]; +			obj->win_mtime[1] = wmtime[1]; +		} + +		obj->dirty = 1; +		result = yaffs_flush_file(obj, 0, 0);  		retVal = 0; +	} else +		/* bad handle */ +		yaffsfs_SetError(-EBADF); + +	yaffsfs_Unlock(); + +	return retVal; +} + +#endif + +static int yaffsfs_DoChMod(struct yaffs_obj *obj, mode_t mode) +{ +	int result = -1; + +	if (obj) +		obj = yaffs_get_equivalent_obj(obj); + +	if (obj) { +		obj->yst_mode = mode; +		obj->dirty = 1; +		result = yaffs_flush_file(obj, 0, 0); +	} + +	return result == YAFFS_OK ? 0 : -1; +} + +int yaffs_access(const YCHAR *path, int amode) +{ +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	int notDir = 0; +	int loop = 0; +	int retval = -1; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1;  	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	if (amode & ~(R_OK | W_OK | X_OK)) { +		yaffsfs_SetError(-EINVAL); +		return -1; +	} + +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); +	obj = yaffsfs_FollowLink(obj, 0, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj) +		yaffsfs_SetError(-ENOENT); +	else if ((amode & W_OK) && obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else { +		int access_ok = 1; + +		if ((amode & R_OK) && !(obj->yst_mode & S_IREAD)) +			access_ok = 0; +		if ((amode & W_OK) && !(obj->yst_mode & S_IWRITE)) +			access_ok = 0; +		if ((amode & X_OK) && !(obj->yst_mode & S_IEXEC)) +			access_ok = 0; + +		if (!access_ok) +			yaffsfs_SetError(-EACCES); +		else +			retval = 0; +	} + +	yaffsfs_Unlock(); + +	return retval; + +} + +int yaffs_chmod(const YCHAR *path, mode_t mode) +{ +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	int retVal = -1; +	int notDir = 0; +	int loop = 0; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	if (mode & ~(0777)) { +		yaffsfs_SetError(-EINVAL); +		return -1; +	} + +	yaffsfs_Lock(); + +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); +	obj = yaffsfs_FollowLink(obj, 0, &loop); + +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj) +		yaffsfs_SetError(-ENOENT); +	else if (obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS);  	else -	{ -		yaffsfs_SetError(-ENOSPC); // just assume no space for now -		retVal = -1; +		retVal = yaffsfs_DoChMod(obj, mode); + +	yaffsfs_Unlock(); + +	return retVal; + +} + +int yaffs_fchmod(int fd, mode_t mode) +{ +	struct yaffs_obj *obj; +	int retVal = -1; + +	if (mode & ~(0777)) { +		yaffsfs_SetError(-EINVAL); +		return -1;  	} +	yaffsfs_Lock(); +	obj = yaffsfs_HandleToObject(fd); + +	if (!obj) +		yaffsfs_SetError(-EBADF); +	else if (obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else +		retVal = yaffsfs_DoChMod(obj, mode); +  	yaffsfs_Unlock();  	return retVal;  } -int yaffs_mount(const char *path) +int yaffs_mkdir(const YCHAR *path, mode_t mode)  { -	int retVal=-1; -	int result=YAFFS_FAIL; -	yaffs_Device *dev=NULL; -	char *dummy; +	struct yaffs_obj *parent = NULL; +	struct yaffs_obj *dir = NULL; +	YCHAR *name; +	YCHAR *alt_path = NULL; +	int retVal = -1; +	int notDir = 0; +	int loop = 0; -	T(YAFFS_TRACE_ALWAYS,("yaffs: Mounting %s\n",path)); +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	if (yaffsfs_alt_dir_path(path, &alt_path) < 0) { +		yaffsfs_SetError(-ENOMEM); +		return -1; +	} +	if (alt_path) +		path = alt_path;  	yaffsfs_Lock(); -	dev = yaffsfs_FindDevice(path,&dummy); -	if(dev) -	{ -		if(!dev->isMounted) -		{ -			result = yaffs_GutsInitialise(dev); -			if(result == YAFFS_FAIL) -			{ -				// todo error - mount failed -				yaffsfs_SetError(-ENOMEM); +	parent = yaffsfs_FindDirectory(NULL, path, &name, 0, ¬Dir, &loop); +	if (!parent && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!parent) +		yaffsfs_SetError(-ENOENT); +	else if (yaffsfs_TooManyObjects(parent->my_dev)) +		yaffsfs_SetError(-ENFILE); +	else if (yaffs_strnlen(name, 5) == 0) { +		/* Trying to make the root itself */ +		yaffsfs_SetError(-EEXIST); +	} else if (parent->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else { +		dir = yaffs_create_dir(parent, name, mode, 0, 0); +		if (dir) +			retVal = 0; +		else if (yaffs_find_by_name(parent, name)) +			yaffsfs_SetError(-EEXIST);	/* name exists */ +		else +			yaffsfs_SetError(-ENOSPC);	/* assume no space */ +	} + +	yaffsfs_Unlock(); + +	kfree(alt_path); + +	return retVal; +} + +int yaffs_rmdir(const YCHAR *path) +{ +	int result; +	YCHAR *alt_path; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	if (yaffsfs_alt_dir_path(path, &alt_path) < 0) { +		yaffsfs_SetError(-ENOMEM); +		return -1; +	} +	if (alt_path) +		path = alt_path; +	result = yaffsfs_DoUnlink(path, 1); + +	kfree(alt_path); + +	return result; +} + +void *yaffs_getdev(const YCHAR *path) +{ +	struct yaffs_dev *dev = NULL; +	YCHAR *dummy; +	dev = yaffsfs_FindDevice(path, &dummy); +	return (void *)dev; +} + +int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt) +{ +	int retVal = -1; +	int result = YAFFS_FAIL; +	struct yaffs_dev *dev = NULL; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	yaffs_trace(YAFFS_TRACE_MOUNT, "yaffs: Mounting %s", path); + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); + +	yaffsfs_InitHandles(); + +	dev = yaffsfs_FindMountPoint(path); +	if (dev) { +		if (!dev->is_mounted) { +			dev->read_only = read_only ? 1 : 0; +			if (skip_checkpt) { +				u8 skip = dev->param.skip_checkpt_rd; +				dev->param.skip_checkpt_rd = 1; +				result = yaffs_guts_initialise(dev); +				dev->param.skip_checkpt_rd = skip; +			} else { +				result = yaffs_guts_initialise(dev);  			} + +			if (result == YAFFS_FAIL) +				yaffsfs_SetError(-ENOMEM);  			retVal = result ? 0 : -1; -		} -		else -		{ -			//todo error - already mounted. +		} else  			yaffsfs_SetError(-EBUSY); -		} -	} -	else -	{ -		// todo error - no device +	} else  		yaffsfs_SetError(-ENODEV); -	} +  	yaffsfs_Unlock();  	return retVal;  } -int yaffs_unmount(const char *path) +int yaffs_mount2(const YCHAR *path, int readonly) +{ +	return yaffs_mount_common(path, readonly, 0); +} + +int yaffs_mount(const YCHAR *path) +{ +	return yaffs_mount_common(path, 0, 0); +} + +int yaffs_sync(const YCHAR *path)  { -	int retVal=-1; -	yaffs_Device *dev=NULL; -	char *dummy; +	int retVal = -1; +	struct yaffs_dev *dev = NULL; +	YCHAR *dummy; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	}  	yaffsfs_Lock(); -	dev = yaffsfs_FindDevice(path,&dummy); -	if(dev) -	{ -		if(dev->isMounted) -		{ -			int i; -			int inUse; +	dev = yaffsfs_FindDevice(path, &dummy); +	if (dev) { +		if (!dev->is_mounted) +			yaffsfs_SetError(-EINVAL); +		else if (dev->read_only) +			yaffsfs_SetError(-EROFS); +		else { -			yaffs_FlushEntireDeviceCache(dev); -			yaffs_CheckpointSave(dev); +			yaffs_flush_whole_cache(dev); +			yaffs_checkpoint_save(dev); +			retVal = 0; -			for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++) -			{ -				if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev) -				{ -					inUse = 1; // the device is in use, can't unmount -				} -			} +		} +	} else +		yaffsfs_SetError(-ENODEV); -			if(!inUse) -			{ -				yaffs_Deinitialise(dev); +	yaffsfs_Unlock(); +	return retVal; +} +static int yaffsfs_IsDevBusy(struct yaffs_dev *dev) +{ +	int i; +	struct yaffs_obj *obj; + +	for (i = 0; i < YAFFSFS_N_HANDLES; i++) { +		obj = yaffsfs_HandleToObject(i); +		if (obj && obj->my_dev == dev) +			return 1; +	} +	return 0; +} + +int yaffs_remount(const YCHAR *path, int force, int read_only) +{ +	int retVal = -1; +	struct yaffs_dev *dev = NULL; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); +	dev = yaffsfs_FindMountPoint(path); +	if (dev) { +		if (dev->is_mounted) { +			yaffs_flush_whole_cache(dev); + +			if (force || !yaffsfs_IsDevBusy(dev)) { +				if (read_only) +					yaffs_checkpoint_save(dev); +				dev->read_only = read_only ? 1 : 0;  				retVal = 0; -			} -			else -			{ -				// todo error can't unmount as files are open +			} else  				yaffsfs_SetError(-EBUSY); -			} -		} -		else -		{ -			//todo error - not mounted. +		} else  			yaffsfs_SetError(-EINVAL); -		} -	} -	else -	{ -		// todo error - no device +	} else  		yaffsfs_SetError(-ENODEV); -	} +  	yaffsfs_Unlock();  	return retVal;  } -loff_t yaffs_freespace(const char *path) +int yaffs_unmount2(const YCHAR *path, int force)  { -	loff_t retVal=-1; -	yaffs_Device *dev=NULL; -	char *dummy; +	int retVal = -1; +	struct yaffs_dev *dev = NULL; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	}  	yaffsfs_Lock(); -	dev = yaffsfs_FindDevice(path,&dummy); -	if(dev  && dev->isMounted) -	{ -		retVal = yaffs_GetNumberOfFreeChunks(dev); -		retVal *= dev->nDataBytesPerChunk; +	dev = yaffsfs_FindMountPoint(path); +	if (dev) { +		if (dev->is_mounted) { +			int inUse; +			yaffs_flush_whole_cache(dev); +			yaffs_checkpoint_save(dev); +			inUse = yaffsfs_IsDevBusy(dev); +			if (!inUse || force) { +				if (inUse) +					yaffsfs_BreakDeviceHandles(dev); +				yaffs_deinitialise(dev); + +				retVal = 0; +			} else +				yaffsfs_SetError(-EBUSY); + +		} else +			yaffsfs_SetError(-EINVAL); + +	} else +		yaffsfs_SetError(-ENODEV); + +	yaffsfs_Unlock(); +	return retVal; +} + +int yaffs_unmount(const YCHAR *path) +{ +	return yaffs_unmount2(path, 0); +} + +loff_t yaffs_freespace(const YCHAR *path) +{ +	loff_t retVal = -1; +	struct yaffs_dev *dev = NULL; +	YCHAR *dummy; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1;  	} -	else -	{ -		yaffsfs_SetError(-EINVAL); + +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1;  	} +	yaffsfs_Lock(); +	dev = yaffsfs_FindDevice(path, &dummy); +	if (dev && dev->is_mounted) { +		retVal = yaffs_get_n_free_chunks(dev); +		retVal *= dev->data_bytes_per_chunk; + +	} else +		yaffsfs_SetError(-EINVAL); +  	yaffsfs_Unlock();  	return retVal;  } +loff_t yaffs_totalspace(const YCHAR *path) +{ +	loff_t retVal = -1; +	struct yaffs_dev *dev = NULL; +	YCHAR *dummy; +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} -void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList) -{ +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); +	dev = yaffsfs_FindDevice(path, &dummy); +	if (dev && dev->is_mounted) { +		retVal = (dev->param.end_block - dev->param.start_block + 1) - +		    dev->param.n_reserved_blocks; +		retVal *= dev->param.chunks_per_block; +		retVal *= dev->data_bytes_per_chunk; + +	} else +		yaffsfs_SetError(-EINVAL); -	yaffsfs_DeviceConfiguration *cfg; +	yaffsfs_Unlock(); +	return retVal; +} -	yaffsfs_configurationList = cfgList; +int yaffs_inodecount(const YCHAR *path) +{ +	loff_t retVal = -1; +	struct yaffs_dev *dev = NULL; +	YCHAR *dummy; -	yaffsfs_InitHandles(); +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} -	cfg = yaffsfs_configurationList; +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} -	while(cfg && cfg->prefix && cfg->dev) -	{ -		cfg->dev->isMounted = 0; -		cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback; -		cfg++; +	yaffsfs_Lock(); +	dev = yaffsfs_FindDevice(path, &dummy); +	if (dev && dev->is_mounted) { +		int n_obj = dev->n_obj; +		if (n_obj > dev->n_hardlinks) +			retVal = n_obj - dev->n_hardlinks;  	} + +	if (retVal < 0) +		yaffsfs_SetError(-EINVAL); + +	yaffsfs_Unlock(); +	return retVal;  } +void yaffs_add_device(struct yaffs_dev *dev) +{ +	struct list_head *cfg; +	/* First check that the device is not in the list. */ + +	list_for_each(cfg, &yaffsfs_deviceList) { +		if (dev == list_entry(cfg, struct yaffs_dev, dev_list)) +			return; +	} -// -// Directory search stuff. +	dev->is_mounted = 0; +	dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback; -// -// Directory search context -// -// NB this is an opaque structure. +	if (!dev->dev_list.next) +		INIT_LIST_HEAD(&dev->dev_list); +	list_add(&dev->dev_list, &yaffsfs_deviceList); +} -typedef struct +void yaffs_remove_device(struct yaffs_dev *dev)  { -	__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; +	list_del_init(&dev->dev_list); +} + +/* Functions to iterate through devices. NB Use with extreme care! */ + +static struct list_head *dev_iterator; +void yaffs_dev_rewind(void) +{ +	dev_iterator = yaffsfs_deviceList.next; +} +struct yaffs_dev *yaffs_next_dev(void) +{ +	struct yaffs_dev *retval; +	if (!dev_iterator) +		return NULL; +	if (dev_iterator == &yaffsfs_deviceList) +		return NULL; -static struct list_head search_contexts; +	retval = list_entry(dev_iterator, struct yaffs_dev, dev_list); +	dev_iterator = dev_iterator->next; +	return retval; +} +/* Directory search stuff. */ -static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc) +static struct list_head search_contexts; + +static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContxt *dsc)  { -	if(dsc && -	   dsc->dirObj && -	   dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){ +	if (dsc && +	    dsc->dirObj && +	    dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { -	   dsc->offset = 0; +		dsc->offset = 0; -	   if( list_empty(&dsc->dirObj->variant.directoryVariant.children)){ -	   	dsc->nextReturn = NULL; -	   } else { -	      	dsc->nextReturn = list_entry(dsc->dirObj->variant.directoryVariant.children.next, -						yaffs_Object,siblings); -	   } +		if (list_empty(&dsc->dirObj->variant.dir_variant.children)) +			dsc->nextReturn = NULL; +		else +			dsc->nextReturn = +			    list_entry(dsc->dirObj->variant.dir_variant. +				       children.next, struct yaffs_obj, +				       siblings);  	} else {  		/* Hey someone isn't playing nice! */  	}  } -static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc) +static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContxt *dsc)  { -	if(dsc && -	   dsc->dirObj && -	   dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){ +	if (dsc && +	    dsc->dirObj && +	    dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { -	   if( dsc->nextReturn == NULL || -	       list_empty(&dsc->dirObj->variant.directoryVariant.children)){ -	   	dsc->nextReturn = NULL; -	   } else { -		   struct list_head *next = dsc->nextReturn->siblings.next; +		if (dsc->nextReturn == NULL || +		    list_empty(&dsc->dirObj->variant.dir_variant.children)) +			dsc->nextReturn = NULL; +		else { +			struct 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); -	   } +			if (next == &dsc->dirObj->variant.dir_variant.children) +				dsc->nextReturn = NULL;	/* end of list */ +			else +				dsc->nextReturn = list_entry(next, +							     struct yaffs_obj, +							     siblings); +		}  	} else {  		/* Hey someone isn't playing nice! */  	}  } -static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj) +static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)  {  	struct list_head *i; -	yaffsfs_DirectorySearchContext *dsc; +	struct yaffsfs_DirSearchContxt *dsc;  	/* if search contexts not initilised then skip */ -	if(!search_contexts.next) +	if (!search_contexts.next)  		return; -	/* Iteratethrough the directory search contexts. +	/* Iterate through 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) { +	list_for_each(i, &search_contexts) {  		if (i) { -			dsc = list_entry(i, yaffsfs_DirectorySearchContext,others); -			if(dsc->nextReturn == obj) +			dsc = list_entry(i, struct yaffsfs_DirSearchContxt, +					 others); +			if (dsc->nextReturn == obj)  				yaffsfs_DirAdvance(dsc);  		}  	}  } -yaffs_DIR *yaffs_opendir(const char *dirname) +yaffs_DIR *yaffs_opendir(const YCHAR *dirname)  {  	yaffs_DIR *dir = NULL; - 	yaffs_Object *obj = NULL; -	yaffsfs_DirectorySearchContext *dsc = NULL; +	struct yaffs_obj *obj = NULL; +	struct yaffsfs_DirSearchContxt *dsc = NULL; +	int notDir = 0; +	int loop = 0; + +	if (!dirname) { +		yaffsfs_SetError(-EFAULT); +		return NULL; +	} + +	if (yaffsfs_CheckPath(dirname) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return NULL; +	}  	yaffsfs_Lock(); -	obj = yaffsfs_FindObject(NULL,dirname,0); +	obj = yaffsfs_FindObject(NULL, dirname, 0, 1, NULL, ¬Dir, &loop); + +	if (!obj && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!obj) +		yaffsfs_SetError(-ENOENT); +	else if (obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) +		yaffsfs_SetError(-ENOTDIR); +	else { +		int i; + +		for (i = 0, dsc = NULL; i < YAFFSFS_N_DSC && !dsc; i++) { +			if (!yaffsfs_dsc[i].inUse) +				dsc = &yaffsfs_dsc[i]; +		} -	if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) -	{ +		dir = (yaffs_DIR *) dsc; -		dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext)); -		dir = (yaffs_DIR *)dsc; -		if(dsc) -		{ -			memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext)); -			dsc->magic = YAFFS_MAGIC; +		if (dsc) { +			memset(dsc, 0, sizeof(struct yaffsfs_DirSearchContxt)); +			dsc->inUse = 1;  			dsc->dirObj = obj; -			strncpy(dsc->name,dirname,NAME_MAX); +			yaffs_strncpy(dsc->name, dirname, NAME_MAX);  			INIT_LIST_HEAD(&dsc->others); -			if(!search_contexts.next) +			if (!search_contexts.next)  				INIT_LIST_HEAD(&search_contexts); -			list_add(&dsc->others,&search_contexts); -			yaffsfs_SetDirRewound(dsc);		} +			list_add(&dsc->others, &search_contexts); +			yaffsfs_SetDirRewound(dsc); +		}  	} @@ -1295,35 +2919,34 @@ yaffs_DIR *yaffs_opendir(const char *dirname)  	return dir;  } -struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) +struct yaffs_dirent *yaffs_readdir(yaffs_DIR * dirp)  { -	yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; +	struct yaffsfs_DirSearchContxt *dsc;  	struct yaffs_dirent *retVal = NULL; +	dsc = (struct yaffsfs_DirSearchContxt *) dirp;  	yaffsfs_Lock(); -	if(dsc && dsc->magic == YAFFS_MAGIC){ +	if (dsc && dsc->inUse) {  		yaffsfs_SetError(0); -		if(dsc->nextReturn){ -			dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId; +		if (dsc->nextReturn) { +			dsc->de.d_ino = +			    yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;  			dsc->de.d_dont_use = (unsigned)dsc->nextReturn;  			dsc->de.d_off = dsc->offset++; -			yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX); -			if(strlen(dsc->de.d_name) == 0) -			{ -				// this should not happen! -				strcpy(dsc->de.d_name,"zz"); +			yaffs_get_obj_name(dsc->nextReturn, +					   dsc->de.d_name, NAME_MAX); +			if (yaffs_strnlen(dsc->de.d_name, NAME_MAX + 1) == 0) { +				/* this should not happen! */ +				yaffs_strcpy(dsc->de.d_name, _Y("zz"));  			}  			dsc->de.d_reclen = sizeof(struct yaffs_dirent);  			retVal = &dsc->de;  			yaffsfs_DirAdvance(dsc);  		} else  			retVal = NULL; -	} -	else -	{ +	} else  		yaffsfs_SetError(-EBADF); -	}  	yaffsfs_Unlock(); @@ -1331,10 +2954,11 @@ struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)  } -  void yaffs_rewinddir(yaffs_DIR *dirp)  { -	yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; +	struct yaffsfs_DirSearchContxt *dsc; + +	dsc = (struct yaffsfs_DirSearchContxt *) dirp;  	yaffsfs_Lock(); @@ -1343,41 +2967,67 @@ void yaffs_rewinddir(yaffs_DIR *dirp)  	yaffsfs_Unlock();  } -  int yaffs_closedir(yaffs_DIR *dirp)  { -	yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; +	struct yaffsfs_DirSearchContxt *dsc; + +	dsc = (struct yaffsfs_DirSearchContxt *) dirp; + +	if (!dsc) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	}  	yaffsfs_Lock(); -	dsc->magic = 0; -	list_del(&dsc->others); /* unhook from list */ -	YFREE(dsc); +	dsc->inUse = 0; +	list_del(&dsc->others);	/* unhook from list */  	yaffsfs_Unlock();  	return 0;  } -// end of directory stuff - +/* End of directory stuff */ -int yaffs_symlink(const char *oldpath, const char *newpath) +int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)  { -	yaffs_Object *parent = NULL; -	yaffs_Object *obj; -	char *name; -	int retVal= -1; -	int mode = 0; // ignore for now +	struct yaffs_obj *parent = NULL; +	struct yaffs_obj *obj; +	YCHAR *name; +	int retVal = -1; +	int mode = 0;		/* ignore for now */ +	int notDir = 0; +	int loop = 0; -	yaffsfs_Lock(); -	parent = yaffsfs_FindDirectory(NULL,newpath,&name,0); -	obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath); -	if(obj) -	{ -		retVal = 0; +	if (!oldpath || !newpath) { +		yaffsfs_SetError(-EFAULT); +		return -1;  	} -	else -	{ -		yaffsfs_SetError(-ENOSPC); // just assume no space for now -		retVal = -1; + +	if (yaffsfs_CheckPath(newpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} + +	yaffsfs_Lock(); +	parent = yaffsfs_FindDirectory(NULL, newpath, &name, 0, ¬Dir, &loop); +	if (!parent && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!parent || yaffs_strnlen(name, 5) < 1) +		yaffsfs_SetError(-ENOENT); +	else if (yaffsfs_TooManyObjects(parent->my_dev)) +		yaffsfs_SetError(-ENFILE); +	else if (parent->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else if (parent) { +		obj = yaffs_create_symlink(parent, name, mode, 0, 0, oldpath); +		if (obj) +			retVal = 0; +		else if (yaffsfs_FindObject +			 (NULL, newpath, 0, 0, NULL, NULL, NULL)) +			yaffsfs_SetError(-EEXIST); +		else +			yaffsfs_SetError(-ENOSPC);  	}  	yaffsfs_Unlock(); @@ -1386,90 +3036,98 @@ int yaffs_symlink(const char *oldpath, const char *newpath)  } -int yaffs_readlink(const char *path, char *buf, int bufsiz) +int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)  { -	yaffs_Object *obj = NULL; -	int retVal; +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *dir = NULL; +	int retVal = -1; +	int notDir = 0; +	int loop = 0; +	if (!path || !buf) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	}  	yaffsfs_Lock(); -	obj = yaffsfs_FindObject(NULL,path,0); +	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); -	if(!obj) -	{ +	if (!dir && notDir) +		yaffsfs_SetError(-ENOTDIR); +	else if (loop) +		yaffsfs_SetError(-ELOOP); +	else if (!dir || !obj)  		yaffsfs_SetError(-ENOENT); -		retVal = -1; -	} -	else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK) -	{ +	else if (obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)  		yaffsfs_SetError(-EINVAL); -		retVal = -1; -	} -	else -	{ -		char *alias = obj->variant.symLinkVariant.alias; -		memset(buf,0,bufsiz); -		strncpy(buf,alias,bufsiz - 1); +	else { +		YCHAR *alias = obj->variant.symlink_variant.alias; +		memset(buf, 0, bufsiz); +		yaffs_strncpy(buf, alias, bufsiz - 1);  		retVal = 0;  	}  	yaffsfs_Unlock();  	return retVal;  } -int yaffs_link(const char *oldpath, const char *newpath) +int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)  { -	// Creates a link called newpath to existing oldpath -	yaffs_Object *obj = NULL; -	yaffs_Object *target = NULL; -	int retVal = 0; +	/* Creates a link called newpath to existing oldpath */ +	struct yaffs_obj *obj = NULL; +	struct yaffs_obj *lnk = NULL; +	struct yaffs_obj *obj_dir = NULL; +	struct yaffs_obj *lnk_dir = NULL; +	int retVal = -1; +	int notDirObj = 0; +	int notDirLnk = 0; +	int objLoop = 0; +	int lnkLoop = 0; +	YCHAR *newname; + +	if (!oldpath || !linkpath) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} +	if (yaffsfs_CheckPath(linkpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	}  	yaffsfs_Lock(); -	obj = yaffsfs_FindObject(NULL,oldpath,0); -	target = yaffsfs_FindObject(NULL,newpath,0); +	obj = yaffsfs_FindObject(NULL, oldpath, 0, 1, +				 &obj_dir, ¬DirObj, &objLoop); +	lnk = yaffsfs_FindObject(NULL, linkpath, 0, 0, NULL, NULL, NULL); +	lnk_dir = yaffsfs_FindDirectory(NULL, linkpath, &newname, +					0, ¬DirLnk, &lnkLoop); -	if(!obj) -	{ +	if ((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk)) +		yaffsfs_SetError(-ENOTDIR); +	else if (objLoop || lnkLoop) +		yaffsfs_SetError(-ELOOP); +	else if (!obj_dir || !lnk_dir || !obj)  		yaffsfs_SetError(-ENOENT); -		retVal = -1; -	} -	else if(target) -	{ +	else if (obj->my_dev->read_only) +		yaffsfs_SetError(-EROFS); +	else if (yaffsfs_TooManyObjects(obj->my_dev)) +		yaffsfs_SetError(-ENFILE); +	else if (lnk)  		yaffsfs_SetError(-EEXIST); -		retVal = -1; -	} -	else -	{ -		yaffs_Object *newdir = NULL; -		yaffs_Object *link = NULL; - -		char *newname; - -		newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0); +	else if (lnk_dir->my_dev != obj->my_dev) +		yaffsfs_SetError(-EXDEV); +	else { +		retVal = yaffsfs_CheckNameLength(newname); -		if(!newdir) -		{ -			yaffsfs_SetError(-ENOTDIR); -			retVal = -1; -		} -		else if(newdir->myDev != obj->myDev) -		{ -			yaffsfs_SetError(-EXDEV); -			retVal = -1; -		} -		if(newdir && strlen(newname) > 0) -		{ -			link = yaffs_Link(newdir,newname,obj); -			if(link) +		if (retVal == 0) { +			lnk = yaffs_link_obj(lnk_dir, newname, obj); +			if (lnk)  				retVal = 0; -			else -			{ +			else {  				yaffsfs_SetError(-ENOSPC);  				retVal = -1;  			} -  		}  	}  	yaffsfs_Unlock(); @@ -1477,34 +3135,84 @@ int yaffs_link(const char *oldpath, const char *newpath)  	return retVal;  } -int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev); +int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev) +{ +	pathname = pathname; +	mode = mode; +	dev = dev; + +	yaffsfs_SetError(-EINVAL); +	return -1; +} + +/* + * D E B U G   F U N C T I O N S + */ -int yaffs_DumpDevStruct(const char *path) +/* + * yaffs_n_handles() + * Returns number of handles attached to the object + */ +int yaffs_n_handles(const YCHAR *path)  { -	char *rest; +	struct yaffs_obj *obj; + +	if (!path) { +		yaffsfs_SetError(-EFAULT); +		return -1; +	} -	yaffs_Object *obj = yaffsfs_FindRoot(path,&rest); +	if (yaffsfs_CheckPath(path) < 0) { +		yaffsfs_SetError(-ENAMETOOLONG); +		return -1; +	} -	if(obj) -	{ -		yaffs_Device *dev = obj->myDev; +	obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL); + +	if (obj) +		return yaffsfs_CountHandles(obj); +	else +		return -1; +} + +int yaffs_get_error(void) +{ +	return yaffsfs_GetLastError(); +} + +int yaffs_set_error(int error) +{ +	yaffsfs_SetError(error); +	return 0; +} + +int yaffs_dump_dev(const YCHAR *path) +{ +#if 1 +	path = path; +#else +	YCHAR *rest; + +	struct yaffs_obj *obj = yaffsfs_FindRoot(path, &rest); + +	if (obj) { +		struct yaffs_dev *dev = obj->my_dev;  		printf("\n" -			   "nPageWrites.......... %d\n" -			   "nPageReads........... %d\n" -			   "nBlockErasures....... %d\n" -			   "nGCCopies............ %d\n" -			   "garbageCollections... %d\n" -			   "passiveGarbageColl'ns %d\n" -			   "\n", -				dev->nPageWrites, -				dev->nPageReads, -				dev->nBlockErasures, -				dev->nGCCopies, -				dev->garbageCollections, -				dev->passiveGarbageCollections -		); +		       "n_page_writes.......... %d\n" +		       "n_page_reads........... %d\n" +		       "n_erasures....... %d\n" +		       "n_gc_copies............ %d\n" +		       "garbageCollections... %d\n" +		       "passiveGarbageColl'ns %d\n" +		       "\n", +		       dev->n_page_writes, +		       dev->n_page_reads, +		       dev->n_erasures, +		       dev->n_gc_copies, +		       dev->garbageCollections, dev->passiveGarbageCollections);  	} +#endif  	return 0;  } |