xref: /openbmc/u-boot/fs/yaffs2/yaffsfs.c (revision fbe502e9aba098b5ad500d1cdb6b376f56f9ddbb)
1  /*
2   * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3   *
4   * Copyright (C) 2002-2011 Aleph One Ltd.
5   *   for Toby Churchill Ltd and Brightstar Engineering
6   *
7   * Created by Charles Manning <charles@aleph1.co.uk>
8   *
9   * This program is free software; you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License version 2 as
11   * published by the Free Software Foundation.
12   */
13  
14  #include <div64.h>
15  #include "yaffsfs.h"
16  #include "yaffs_guts.h"
17  #include "yaffscfg.h"
18  #include "yportenv.h"
19  #include "yaffs_trace.h"
20  
21  #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
22  
23  #ifndef NULL
24  #define NULL ((void *)0)
25  #endif
26  
27  /* YAFFSFS_RW_SIZE must be a power of 2 */
28  #define YAFFSFS_RW_SHIFT (13)
29  #define YAFFSFS_RW_SIZE  (1<<YAFFSFS_RW_SHIFT)
30  
31  /* Some forward references */
32  static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory,
33  					    const YCHAR *path,
34  					    int symDepth, int getEquiv,
35  					    struct yaffs_obj **dirOut,
36  					    int *notDir, int *loop);
37  
38  static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj);
39  
40  unsigned int yaffs_wr_attempts;
41  
42  /*
43   * Handle management.
44   * There are open inodes in struct yaffsfs_Inode.
45   * There are open file descriptors in yaffsfs_FileDes.
46   * There are open handles in yaffsfs_FileDes.
47   *
48   * Things are structured this way to be like the Linux VFS model
49   * so that interactions with the yaffs guts calls are similar.
50   * That means more common code paths and less special code.
51   * That means better testing etc.
52   *
53   * We have 3 layers because:
54   * A handle is different than an fd because you can use dup()
55   * to create a new handle that accesses the *same* fd. The two
56   * handles will use the same offset (part of the fd). We only close
57   * down the fd when there are no more handles accessing it.
58   *
59   * More than one fd can currently access one file, but each fd
60   * has its own permsiions and offset.
61   */
62  
63  struct yaffsfs_Inode {
64  	int count;		/* Number of handles accessing this inode */
65  	struct yaffs_obj *iObj;
66  };
67  
68  struct yaffsfs_FileDes {
69  	u8 reading:1;
70  	u8 writing:1;
71  	u8 append:1;
72  	u8 shareRead:1;
73  	u8 shareWrite:1;
74  	int inodeId:12;		/* Index to corresponding yaffsfs_Inode */
75  	int handleCount:10;	/* Number of handles for this fd */
76  	loff_t position;	/* current position in file */
77  };
78  
79  struct yaffsfs_Handle {
80  	short int fdId;
81  	short int useCount;
82  };
83  
84  
85  struct yaffsfs_DirSearchContxt {
86  	struct yaffs_dirent de;	/* directory entry */
87  	YCHAR name[NAME_MAX + 1];	/* name of directory being searched */
88  	struct yaffs_obj *dirObj;	/* ptr to directory being searched */
89  	struct yaffs_obj *nextReturn;	/* obj  returned by next readddir */
90  	struct list_head others;
91  	int offset:20;
92  	unsigned inUse:1;
93  };
94  
95  static struct yaffsfs_DirSearchContxt yaffsfs_dsc[YAFFSFS_N_DSC];
96  static struct yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
97  static struct yaffsfs_FileDes yaffsfs_fd[YAFFSFS_N_HANDLES];
98  static struct yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
99  
100  static int yaffsfs_handlesInitialised;
101  
102  unsigned yaffs_set_trace(unsigned tm)
103  {
104  	yaffs_trace_mask = tm;
105  	return yaffs_trace_mask;
106  }
107  
108  unsigned yaffs_get_trace(void)
109  {
110  	return yaffs_trace_mask;
111  }
112  
113  /*
114   * yaffsfs_InitHandle
115   * Inilitalise handle management on start-up.
116   */
117  
118  static void yaffsfs_InitHandles(void)
119  {
120  	int i;
121  	if (yaffsfs_handlesInitialised)
122  		return;
123  
124  	memset(yaffsfs_inode, 0, sizeof(yaffsfs_inode));
125  	memset(yaffsfs_fd, 0, sizeof(yaffsfs_fd));
126  	memset(yaffsfs_handle, 0, sizeof(yaffsfs_handle));
127  	memset(yaffsfs_dsc, 0, sizeof(yaffsfs_dsc));
128  
129  	for (i = 0; i < YAFFSFS_N_HANDLES; i++)
130  		yaffsfs_fd[i].inodeId = -1;
131  	for (i = 0; i < YAFFSFS_N_HANDLES; i++)
132  		yaffsfs_handle[i].fdId = -1;
133  }
134  
135  static struct yaffsfs_Handle *yaffsfs_HandleToPointer(int h)
136  {
137  	if (h >= 0 && h < YAFFSFS_N_HANDLES)
138  		return &yaffsfs_handle[h];
139  	return NULL;
140  }
141  
142  static struct yaffsfs_FileDes *yaffsfs_HandleToFileDes(int handle)
143  {
144  	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
145  
146  	if (h && h->useCount > 0 && h->fdId >= 0 && h->fdId < YAFFSFS_N_HANDLES)
147  		return &yaffsfs_fd[h->fdId];
148  
149  	return NULL;
150  }
151  
152  static struct yaffsfs_Inode *yaffsfs_HandleToInode(int handle)
153  {
154  	struct yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle);
155  
156  	if (fd && fd->handleCount > 0 &&
157  	    fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES)
158  		return &yaffsfs_inode[fd->inodeId];
159  
160  	return NULL;
161  }
162  
163  static struct yaffs_obj *yaffsfs_HandleToObject(int handle)
164  {
165  	struct yaffsfs_Inode *in = yaffsfs_HandleToInode(handle);
166  
167  	if (in)
168  		return in->iObj;
169  
170  	return NULL;
171  }
172  
173  /*
174   * yaffsfs_FindInodeIdForObject
175   * Find the inode entry for an object, if it exists.
176   */
177  
178  static int yaffsfs_FindInodeIdForObject(struct yaffs_obj *obj)
179  {
180  	int i;
181  	int ret = -1;
182  
183  	if (obj)
184  		obj = yaffs_get_equivalent_obj(obj);
185  
186  	/* Look for it in open inode table */
187  	for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) {
188  		if (yaffsfs_inode[i].iObj == obj)
189  			ret = i;
190  	}
191  	return ret;
192  }
193  
194  /*
195   * yaffsfs_GetInodeIdForObject
196   * Grab an inode entry when opening a new inode.
197   */
198  static int yaffsfs_GetInodeIdForObject(struct yaffs_obj *obj)
199  {
200  	int i;
201  	int ret;
202  	struct yaffsfs_Inode *in = NULL;
203  
204  	if (obj)
205  		obj = yaffs_get_equivalent_obj(obj);
206  
207  	ret = yaffsfs_FindInodeIdForObject(obj);
208  
209  	for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) {
210  		if (!yaffsfs_inode[i].iObj)
211  			ret = i;
212  	}
213  
214  	if (ret >= 0) {
215  		in = &yaffsfs_inode[ret];
216  		if (!in->iObj)
217  			in->count = 0;
218  		in->iObj = obj;
219  		in->count++;
220  	}
221  
222  	return ret;
223  }
224  
225  static int yaffsfs_CountHandles(struct yaffs_obj *obj)
226  {
227  	int i = yaffsfs_FindInodeIdForObject(obj);
228  
229  	if (i >= 0)
230  		return yaffsfs_inode[i].count;
231  	else
232  		return 0;
233  }
234  
235  static void yaffsfs_ReleaseInode(struct yaffsfs_Inode *in)
236  {
237  	struct yaffs_obj *obj;
238  
239  	obj = in->iObj;
240  
241  	if (obj->unlinked)
242  		yaffs_del_obj(obj);
243  
244  	obj->my_inode = NULL;
245  	in->iObj = NULL;
246  
247  }
248  
249  static void yaffsfs_PutInode(int inodeId)
250  {
251  	if (inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES) {
252  		struct yaffsfs_Inode *in = &yaffsfs_inode[inodeId];
253  		in->count--;
254  		if (in->count <= 0) {
255  			yaffsfs_ReleaseInode(in);
256  			in->count = 0;
257  		}
258  	}
259  }
260  
261  static int yaffsfs_NewHandle(struct yaffsfs_Handle **hptr)
262  {
263  	int i;
264  	struct yaffsfs_Handle *h;
265  
266  	for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
267  		h = &yaffsfs_handle[i];
268  		if (h->useCount < 1) {
269  			memset(h, 0, sizeof(struct yaffsfs_Handle));
270  			h->fdId = -1;
271  			h->useCount = 1;
272  			if (hptr)
273  				*hptr = h;
274  			return i;
275  		}
276  	}
277  	return -1;
278  }
279  
280  static int yaffsfs_NewHandleAndFileDes(void)
281  {
282  	int i;
283  	struct yaffsfs_FileDes *fd;
284  	struct yaffsfs_Handle *h = NULL;
285  	int handle = yaffsfs_NewHandle(&h);
286  
287  	if (handle < 0)
288  		return -1;
289  
290  	for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
291  		fd = &yaffsfs_fd[i];
292  		if (fd->handleCount < 1) {
293  			memset(fd, 0, sizeof(struct yaffsfs_FileDes));
294  			fd->inodeId = -1;
295  			fd->handleCount = 1;
296  			h->fdId = i;
297  			return handle;
298  		}
299  	}
300  
301  	/* Dump the handle because we could not get a fd */
302  	h->useCount = 0;
303  	return -1;
304  }
305  
306  /*
307   * yaffs_get_handle
308   * Increase use of handle when reading/writing a file
309   * Also gets the file descriptor.
310   */
311  
312  static int yaffsfs_GetHandle(int handle)
313  {
314  	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
315  
316  	if (h && h->useCount > 0) {
317  		h->useCount++;
318  		return 0;
319  	}
320  	return -1;
321  }
322  
323  /*
324   * yaffs_put_handle
325   * Let go of a handle when closing a file or aborting an open or
326   * ending a read or write.
327   */
328  
329  static int yaffsfs_PutFileDes(int fdId)
330  {
331  	struct yaffsfs_FileDes *fd;
332  
333  	if (fdId >= 0 && fdId < YAFFSFS_N_HANDLES) {
334  		fd = &yaffsfs_fd[fdId];
335  		fd->handleCount--;
336  		if (fd->handleCount < 1) {
337  			if (fd->inodeId >= 0) {
338  				yaffsfs_PutInode(fd->inodeId);
339  				fd->inodeId = -1;
340  			}
341  		}
342  	}
343  	return 0;
344  }
345  
346  static int yaffsfs_PutHandle(int handle)
347  {
348  	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
349  
350  	if (h && h->useCount > 0) {
351  		h->useCount--;
352  		if (h->useCount < 1) {
353  			yaffsfs_PutFileDes(h->fdId);
354  			h->fdId = -1;
355  		}
356  	}
357  
358  	return 0;
359  }
360  
361  static void yaffsfs_BreakDeviceHandles(struct yaffs_dev *dev)
362  {
363  	struct yaffsfs_FileDes *fd;
364  	struct yaffsfs_Handle *h;
365  	struct yaffs_obj *obj;
366  	int i;
367  	for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
368  		h = yaffsfs_HandleToPointer(i);
369  		fd = yaffsfs_HandleToFileDes(i);
370  		obj = yaffsfs_HandleToObject(i);
371  		if (h && h->useCount > 0) {
372  			h->useCount = 0;
373  			h->fdId = 0;
374  		}
375  		if (fd && fd->handleCount > 0 && obj && obj->my_dev == dev) {
376  			fd->handleCount = 0;
377  			yaffsfs_PutInode(fd->inodeId);
378  			fd->inodeId = -1;
379  		}
380  	}
381  }
382  
383  /*
384   *  Stuff to handle names.
385   */
386  #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
387  
388  static int yaffs_toupper(YCHAR a)
389  {
390  	if (a >= 'a' && a <= 'z')
391  		return (a - 'a') + 'A';
392  	else
393  		return a;
394  }
395  
396  int yaffsfs_Match(YCHAR a, YCHAR b)
397  {
398  	return (yaffs_toupper(a) == yaffs_toupper(b));
399  }
400  #else
401  int yaffsfs_Match(YCHAR a, YCHAR b)
402  {
403  	/* case sensitive */
404  	return (a == b);
405  }
406  #endif
407  
408  int yaffsfs_IsPathDivider(YCHAR ch)
409  {
410  	const YCHAR *str = YAFFS_PATH_DIVIDERS;
411  
412  	while (*str) {
413  		if (*str == ch)
414  			return 1;
415  		str++;
416  	}
417  
418  	return 0;
419  }
420  
421  int yaffsfs_CheckNameLength(const char *name)
422  {
423  	int retVal = 0;
424  
425  	int nameLength = yaffs_strnlen(name, YAFFS_MAX_NAME_LENGTH + 1);
426  
427  	if (nameLength == 0) {
428  		yaffsfs_SetError(-ENOENT);
429  		retVal = -1;
430  	} else if (nameLength > YAFFS_MAX_NAME_LENGTH) {
431  		yaffsfs_SetError(-ENAMETOOLONG);
432  		retVal = -1;
433  	}
434  
435  	return retVal;
436  }
437  
438  static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path)
439  {
440  	YCHAR *alt_path = NULL;
441  	int path_length;
442  	int i;
443  
444  	/*
445  	 * We don't have a definition for max path length.
446  	 * We will use 3 * max name length instead.
447  	 */
448  	*ret_path = NULL;
449  	path_length = yaffs_strnlen(path, (YAFFS_MAX_NAME_LENGTH + 1) * 3 + 1);
450  
451  	/* If the last character is a path divider, then we need to
452  	 * trim it back so that the name look-up works properly.
453  	 * eg. /foo/new_dir/ -> /foo/newdir
454  	 * Curveball: Need to handle multiple path dividers:
455  	 * eg. /foof/sdfse///// -> /foo/sdfse
456  	 */
457  	if (path_length > 0 && yaffsfs_IsPathDivider(path[path_length - 1])) {
458  		alt_path = kmalloc(path_length + 1, 0);
459  		if (!alt_path)
460  			return -1;
461  		yaffs_strcpy(alt_path, path);
462  		for (i = path_length - 1;
463  		     i >= 0 && yaffsfs_IsPathDivider(alt_path[i]); i--)
464  			alt_path[i] = (YCHAR) 0;
465  	}
466  	*ret_path = alt_path;
467  	return 0;
468  }
469  
470  LIST_HEAD(yaffsfs_deviceList);
471  
472  /*
473   * yaffsfs_FindDevice
474   * yaffsfs_FindRoot
475   * Scan the configuration list to find the device
476   * Curveballs: Should match paths that end in '/' too
477   * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
478   */
479  static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path,
480  					    YCHAR **restOfPath)
481  {
482  	struct list_head *cfg;
483  	const YCHAR *leftOver;
484  	const YCHAR *p;
485  	struct yaffs_dev *retval = NULL;
486  	struct yaffs_dev *dev = NULL;
487  	int thisMatchLength;
488  	int longestMatch = -1;
489  	int matching;
490  
491  	/*
492  	 * Check all configs, choose the one that:
493  	 * 1) Actually matches a prefix (ie /a amd /abc will not match
494  	 * 2) Matches the longest.
495  	 */
496  	list_for_each(cfg, &yaffsfs_deviceList) {
497  		dev = list_entry(cfg, struct yaffs_dev, dev_list);
498  		leftOver = path;
499  		p = dev->param.name;
500  		thisMatchLength = 0;
501  		matching = 1;
502  
503  		while (matching && *p && *leftOver) {
504  			/* Skip over any /s */
505  			while (yaffsfs_IsPathDivider(*p))
506  				p++;
507  
508  			/* Skip over any /s */
509  			while (yaffsfs_IsPathDivider(*leftOver))
510  				leftOver++;
511  
512  			/* Now match the text part */
513  			while (matching &&
514  			       *p && !yaffsfs_IsPathDivider(*p) &&
515  			       *leftOver && !yaffsfs_IsPathDivider(*leftOver)) {
516  				if (yaffsfs_Match(*p, *leftOver)) {
517  					p++;
518  					leftOver++;
519  					thisMatchLength++;
520  				} else {
521  					matching = 0;
522  				}
523  			}
524  		}
525  
526  		/* Skip over any /s in leftOver */
527  		while (yaffsfs_IsPathDivider(*leftOver))
528  			leftOver++;
529  
530  		/*Skip over any /s in p */
531  		while (yaffsfs_IsPathDivider(*p))
532  			p++;
533  
534  		/* p should now be at the end of the string if fully matched */
535  		if (*p)
536  			matching = 0;
537  
538  		if (matching && (thisMatchLength > longestMatch)) {
539  			/* Matched prefix */
540  			*restOfPath = (YCHAR *) leftOver;
541  			retval = dev;
542  			longestMatch = thisMatchLength;
543  		}
544  
545  	}
546  	return retval;
547  }
548  
549  static int yaffsfs_CheckPath(const YCHAR *path)
550  {
551  	int n = 0;
552  	int divs = 0;
553  
554  	while (*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100) {
555  		if (yaffsfs_IsPathDivider(*path)) {
556  			n = 0;
557  			divs++;
558  		} else
559  			n++;
560  		path++;
561  	}
562  
563  	return (*path) ? -1 : 0;
564  }
565  
566  /* FindMountPoint only returns a dev entry if the path is a mount point */
567  static struct yaffs_dev *yaffsfs_FindMountPoint(const YCHAR *path)
568  {
569  	struct yaffs_dev *dev;
570  	YCHAR *restOfPath = NULL;
571  
572  	dev = yaffsfs_FindDevice(path, &restOfPath);
573  	if (dev && restOfPath && *restOfPath)
574  		dev = NULL;
575  	return dev;
576  }
577  
578  static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path,
579  					  YCHAR **restOfPath)
580  {
581  	struct yaffs_dev *dev;
582  
583  	dev = yaffsfs_FindDevice(path, restOfPath);
584  	if (dev && dev->is_mounted)
585  		return dev->root_dir;
586  
587  	return NULL;
588  }
589  
590  static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj,
591  					    int symDepth, int *loop)
592  {
593  
594  	if (obj)
595  		obj = yaffs_get_equivalent_obj(obj);
596  
597  	while (obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
598  		YCHAR *alias = obj->variant.symlink_variant.alias;
599  
600  		if (yaffsfs_IsPathDivider(*alias))
601  			/* Starts with a /, need to scan from root up */
602  			obj = yaffsfs_FindObject(NULL, alias, symDepth++,
603  						 1, NULL, NULL, loop);
604  		else
605  			/*
606  			 * Relative to here so use the parent of the
607  			 * symlink as a start
608  			 */
609  			obj = yaffsfs_FindObject(obj->parent, alias, symDepth++,
610  						 1, NULL, NULL, loop);
611  	}
612  	return obj;
613  }
614  
615  /*
616   * yaffsfs_FindDirectory
617   * Parse a path to determine the directory and the name within the directory.
618   *
619   * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
620   */
621  static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir,
622  						 const YCHAR *path,
623  						 YCHAR **name, int symDepth,
624  						 int *notDir, int *loop)
625  {
626  	struct yaffs_obj *dir;
627  	YCHAR *restOfPath;
628  	YCHAR str[YAFFS_MAX_NAME_LENGTH + 1];
629  	int i;
630  
631  	if (symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) {
632  		if (loop)
633  			*loop = 1;
634  		return NULL;
635  	}
636  
637  	if (startDir) {
638  		dir = startDir;
639  		restOfPath = (YCHAR *) path;
640  	} else
641  		dir = yaffsfs_FindRoot(path, &restOfPath);
642  
643  	while (dir) {
644  		/*
645  		 * parse off /.
646  		 * curve ball: also throw away surplus '/'
647  		 * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
648  		 */
649  		while (yaffsfs_IsPathDivider(*restOfPath))
650  			restOfPath++;	/* get rid of '/' */
651  
652  		*name = restOfPath;
653  		i = 0;
654  
655  		while (*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)) {
656  			if (i < YAFFS_MAX_NAME_LENGTH) {
657  				str[i] = *restOfPath;
658  				str[i + 1] = '\0';
659  				i++;
660  			}
661  			restOfPath++;
662  		}
663  
664  		if (!*restOfPath)
665  			/* got to the end of the string */
666  			return dir;
667  		else {
668  			if (yaffs_strcmp(str, _Y(".")) == 0) {
669  				/* Do nothing */
670  			} else if (yaffs_strcmp(str, _Y("..")) == 0) {
671  				dir = dir->parent;
672  			} else {
673  				dir = yaffs_find_by_name(dir, str);
674  
675  				dir = yaffsfs_FollowLink(dir, symDepth, loop);
676  
677  				if (dir && dir->variant_type !=
678  				    YAFFS_OBJECT_TYPE_DIRECTORY) {
679  					if (notDir)
680  						*notDir = 1;
681  					dir = NULL;
682  				}
683  
684  			}
685  		}
686  	}
687  	/* directory did not exist. */
688  	return NULL;
689  }
690  
691  static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relDir,
692  					       const YCHAR *path,
693  					       YCHAR **name,
694  					       int symDepth,
695  					       int *notDir, int *loop)
696  {
697  	return yaffsfs_DoFindDirectory(relDir, path, name, symDepth, notDir,
698  						loop);
699  }
700  
701  /*
702   * yaffsfs_FindObject turns a path for an existing object into the object
703   */
704  static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relDir,
705  					    const YCHAR *path, int symDepth,
706  					    int getEquiv,
707  					    struct yaffs_obj **dirOut,
708  					    int *notDir, int *loop)
709  {
710  	struct yaffs_obj *dir;
711  	struct yaffs_obj *obj;
712  	YCHAR *name;
713  
714  	dir =
715  	    yaffsfs_FindDirectory(relDir, path, &name, symDepth, notDir, loop);
716  
717  	if (dirOut)
718  		*dirOut = dir;
719  
720  	if (dir && *name)
721  		obj = yaffs_find_by_name(dir, name);
722  	else
723  		obj = dir;
724  
725  	if (getEquiv)
726  		obj = yaffs_get_equivalent_obj(obj);
727  
728  	return obj;
729  }
730  
731  /*************************************************************************
732   *	Start of yaffsfs visible functions.
733   *************************************************************************/
734  
735  int yaffs_dup(int handle)
736  {
737  	int newHandleNumber = -1;
738  	struct yaffsfs_FileDes *existingFD = NULL;
739  	struct yaffsfs_Handle *existingHandle = NULL;
740  	struct yaffsfs_Handle *newHandle = NULL;
741  
742  	yaffsfs_Lock();
743  	existingHandle = yaffsfs_HandleToPointer(handle);
744  	existingFD = yaffsfs_HandleToFileDes(handle);
745  	if (existingFD)
746  		newHandleNumber = yaffsfs_NewHandle(&newHandle);
747  	if (newHandle) {
748  		newHandle->fdId = existingHandle->fdId;
749  		existingFD->handleCount++;
750  	}
751  
752  	yaffsfs_Unlock();
753  
754  	if (!existingFD)
755  		yaffsfs_SetError(-EBADF);
756  	else if (!newHandle)
757  		yaffsfs_SetError(-ENOMEM);
758  
759  	return newHandleNumber;
760  
761  }
762  
763  static int yaffsfs_TooManyObjects(struct yaffs_dev *dev)
764  {
765  	int current_objects = dev->n_obj - dev->n_deleted_files;
766  
767  	if (dev->param.max_objects && current_objects > dev->param.max_objects)
768  		return 1;
769  	else
770  		return 0;
771  }
772  
773  int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
774  {
775  	struct yaffs_obj *obj = NULL;
776  	struct yaffs_obj *dir = NULL;
777  	YCHAR *name;
778  	int handle = -1;
779  	struct yaffsfs_FileDes *fd = NULL;
780  	int openDenied = 0;
781  	int symDepth = 0;
782  	int errorReported = 0;
783  	int rwflags = oflag & (O_RDWR | O_RDONLY | O_WRONLY);
784  	u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0;
785  	u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0;
786  	u8 sharedReadAllowed;
787  	u8 sharedWriteAllowed;
788  	u8 alreadyReading;
789  	u8 alreadyWriting;
790  	u8 readRequested;
791  	u8 writeRequested;
792  	int notDir = 0;
793  	int loop = 0;
794  
795  	if (!path) {
796  		yaffsfs_SetError(-EFAULT);
797  		return -1;
798  	}
799  
800  	if (yaffsfs_CheckPath(path) < 0) {
801  		yaffsfs_SetError(-ENAMETOOLONG);
802  		return -1;
803  	}
804  
805  	/* O_EXCL only has meaning if O_CREAT is specified */
806  	if (!(oflag & O_CREAT))
807  		oflag &= ~(O_EXCL);
808  
809  	/* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
810  	if ((oflag & O_CREAT) & (oflag & O_EXCL))
811  		oflag &= ~(O_TRUNC);
812  
813  	/* Todo: Are there any more flag combos to sanitise ? */
814  
815  	/* Figure out if reading or writing is requested */
816  
817  	readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0;
818  	writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0;
819  
820  	yaffsfs_Lock();
821  
822  	handle = yaffsfs_NewHandleAndFileDes();
823  
824  	if (handle < 0) {
825  		yaffsfs_SetError(-ENFILE);
826  		errorReported = 1;
827  	} else {
828  
829  		fd = yaffsfs_HandleToFileDes(handle);
830  
831  		/* try to find the exisiting object */
832  		obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL);
833  
834  		obj = yaffsfs_FollowLink(obj, symDepth++, &loop);
835  
836  		if (obj &&
837  		    obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
838  		    obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
839  			obj = NULL;
840  
841  		if (obj) {
842  
843  			/* The file already exists or it might be a directory */
844  
845  			/* A directory can't be opened as a file */
846  			if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
847  				openDenied = 1;
848  				yaffsfs_SetError(-EISDIR);
849  				errorReported = 1;
850  			}
851  
852  			/* Open should fail if O_CREAT and O_EXCL are specified
853  			 * for a file that exists.
854  			 */
855  			if (!errorReported &&
856  			    (oflag & O_EXCL) && (oflag & O_CREAT)) {
857  				openDenied = 1;
858  				yaffsfs_SetError(-EEXIST);
859  				errorReported = 1;
860  			}
861  
862  			/* Check file permissions */
863  			if (readRequested && !(obj->yst_mode & S_IREAD))
864  				openDenied = 1;
865  
866  			if (writeRequested && !(obj->yst_mode & S_IWRITE))
867  				openDenied = 1;
868  
869  			if (!errorReported && writeRequested &&
870  			    obj->my_dev->read_only) {
871  				openDenied = 1;
872  				yaffsfs_SetError(-EROFS);
873  				errorReported = 1;
874  			}
875  
876  			if (openDenied && !errorReported) {
877  				yaffsfs_SetError(-EACCES);
878  				errorReported = 1;
879  			}
880  
881  			/* Check sharing of an existing object. */
882  			if (!openDenied) {
883  				struct yaffsfs_FileDes *fdx;
884  				int i;
885  
886  				sharedReadAllowed = 1;
887  				sharedWriteAllowed = 1;
888  				alreadyReading = 0;
889  				alreadyWriting = 0;
890  				for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
891  					fdx = &yaffsfs_fd[i];
892  					if (fdx->handleCount > 0 &&
893  					    fdx->inodeId >= 0 &&
894  					    yaffsfs_inode[fdx->inodeId].iObj
895  					    == obj) {
896  						if (!fdx->shareRead)
897  							sharedReadAllowed = 0;
898  						if (!fdx->shareWrite)
899  							sharedWriteAllowed = 0;
900  						if (fdx->reading)
901  							alreadyReading = 1;
902  						if (fdx->writing)
903  							alreadyWriting = 1;
904  					}
905  				}
906  
907  				if ((!sharedReadAllowed && readRequested) ||
908  				    (!shareRead && alreadyReading) ||
909  				    (!sharedWriteAllowed && writeRequested) ||
910  				    (!shareWrite && alreadyWriting)) {
911  					openDenied = 1;
912  					yaffsfs_SetError(-EBUSY);
913  					errorReported = 1;
914  				}
915  			}
916  
917  		}
918  
919  		/* If we could not open an existing object, then let's see if
920  		 * the directory exists. If not, error.
921  		 */
922  		if (!obj && !errorReported) {
923  			dir = yaffsfs_FindDirectory(NULL, path, &name, 0,
924  						    &notDir, &loop);
925  			if (!dir && notDir) {
926  				yaffsfs_SetError(-ENOTDIR);
927  				errorReported = 1;
928  			} else if (loop) {
929  				yaffsfs_SetError(-ELOOP);
930  				errorReported = 1;
931  			} else if (!dir) {
932  				yaffsfs_SetError(-ENOENT);
933  				errorReported = 1;
934  			}
935  		}
936  
937  		if (!obj && dir && !errorReported && (oflag & O_CREAT)) {
938  			/* Let's see if we can create this file */
939  			if (dir->my_dev->read_only) {
940  				yaffsfs_SetError(-EROFS);
941  				errorReported = 1;
942  			} else if (yaffsfs_TooManyObjects(dir->my_dev)) {
943  				yaffsfs_SetError(-ENFILE);
944  				errorReported = 1;
945  			} else
946  				obj = yaffs_create_file(dir, name, mode, 0, 0);
947  
948  			if (!obj && !errorReported) {
949  				yaffsfs_SetError(-ENOSPC);
950  				errorReported = 1;
951  			}
952  		}
953  
954  		if (!obj && dir && !errorReported && !(oflag & O_CREAT)) {
955  			yaffsfs_SetError(-ENOENT);
956  			errorReported = 1;
957  		}
958  
959  		if (obj && !openDenied) {
960  			int inodeId = yaffsfs_GetInodeIdForObject(obj);
961  
962  			if (inodeId < 0) {
963  				/*
964  				 * Todo: Fix any problem if inodes run out,
965  				 * That can't happen if the number of inode
966  				 * items >= number of handles.
967  				 */
968  			}
969  
970  			fd->inodeId = inodeId;
971  			fd->reading = readRequested;
972  			fd->writing = writeRequested;
973  			fd->append = (oflag & O_APPEND) ? 1 : 0;
974  			fd->position = 0;
975  			fd->shareRead = shareRead;
976  			fd->shareWrite = shareWrite;
977  
978  			/* Hook inode to object */
979  			obj->my_inode = (void *)&yaffsfs_inode[inodeId];
980  
981  			if ((oflag & O_TRUNC) && fd->writing)
982  				yaffs_resize_file(obj, 0);
983  		} else {
984  			yaffsfs_PutHandle(handle);
985  			if (!errorReported)
986  				yaffsfs_SetError(0);	/* Problem */
987  			handle = -1;
988  		}
989  	}
990  
991  	yaffsfs_Unlock();
992  
993  	return handle;
994  }
995  
996  int yaffs_open(const YCHAR *path, int oflag, int mode)
997  {
998  	return yaffs_open_sharing(path, oflag, mode,
999  				  YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
1000  }
1001  
1002  int yaffs_Dofsync(int handle, int datasync)
1003  {
1004  	int retVal = -1;
1005  	struct yaffs_obj *obj;
1006  
1007  	yaffsfs_Lock();
1008  
1009  	obj = yaffsfs_HandleToObject(handle);
1010  
1011  	if (!obj)
1012  		yaffsfs_SetError(-EBADF);
1013  	else if (obj->my_dev->read_only)
1014  		yaffsfs_SetError(-EROFS);
1015  	else {
1016  		yaffs_flush_file(obj, 1, datasync);
1017  		retVal = 0;
1018  	}
1019  
1020  	yaffsfs_Unlock();
1021  
1022  	return retVal;
1023  }
1024  
1025  int yaffs_fsync(int handle)
1026  {
1027  	return yaffs_Dofsync(handle, 0);
1028  }
1029  
1030  int yaffs_flush(int handle)
1031  {
1032  	return yaffs_fsync(handle);
1033  }
1034  
1035  int yaffs_fdatasync(int handle)
1036  {
1037  	return yaffs_Dofsync(handle, 1);
1038  }
1039  
1040  int yaffs_close(int handle)
1041  {
1042  	struct yaffsfs_Handle *h = NULL;
1043  	struct yaffs_obj *obj = NULL;
1044  	int retVal = -1;
1045  
1046  	yaffsfs_Lock();
1047  
1048  	h = yaffsfs_HandleToPointer(handle);
1049  	obj = yaffsfs_HandleToObject(handle);
1050  
1051  	if (!h || !obj)
1052  		yaffsfs_SetError(-EBADF);
1053  	else {
1054  		/* clean up */
1055  		yaffs_flush_file(obj, 1, 0);
1056  		yaffsfs_PutHandle(handle);
1057  		retVal = 0;
1058  	}
1059  
1060  	yaffsfs_Unlock();
1061  
1062  	return retVal;
1063  }
1064  
1065  int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte,
1066  		    int isPread, loff_t offset)
1067  {
1068  	struct yaffsfs_FileDes *fd = NULL;
1069  	struct yaffs_obj *obj = NULL;
1070  	loff_t pos = 0;
1071  	loff_t startPos = 0;
1072  	loff_t endPos = 0;
1073  	int nRead = 0;
1074  	int nToRead = 0;
1075  	int totalRead = 0;
1076  	loff_t maxRead;
1077  	u8 *buf = (u8 *) vbuf;
1078  
1079  	if (!vbuf) {
1080  		yaffsfs_SetError(-EFAULT);
1081  		return -1;
1082  	}
1083  
1084  	yaffsfs_Lock();
1085  	fd = yaffsfs_HandleToFileDes(handle);
1086  	obj = yaffsfs_HandleToObject(handle);
1087  
1088  	if (!fd || !obj) {
1089  		/* bad handle */
1090  		yaffsfs_SetError(-EBADF);
1091  		totalRead = -1;
1092  	} else if (!fd->reading) {
1093  		/* Not a reading handle */
1094  		yaffsfs_SetError(-EINVAL);
1095  		totalRead = -1;
1096  	} else if (nbyte > YAFFS_MAX_FILE_SIZE) {
1097  		yaffsfs_SetError(-EINVAL);
1098  		totalRead = -1;
1099  	} else {
1100  		if (isPread)
1101  			startPos = offset;
1102  		else
1103  			startPos = fd->position;
1104  
1105  		pos = startPos;
1106  
1107  		if (yaffs_get_obj_length(obj) > pos)
1108  			maxRead = yaffs_get_obj_length(obj) - pos;
1109  		else
1110  			maxRead = 0;
1111  
1112  		if (nbyte > maxRead)
1113  			nbyte = maxRead;
1114  
1115  		yaffsfs_GetHandle(handle);
1116  
1117  		endPos = pos + nbyte;
1118  
1119  		if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
1120  		    nbyte > YAFFS_MAX_FILE_SIZE ||
1121  		    endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
1122  			totalRead = -1;
1123  			nbyte = 0;
1124  		}
1125  
1126  		while (nbyte > 0) {
1127  			nToRead = YAFFSFS_RW_SIZE -
1128  			    (pos & (YAFFSFS_RW_SIZE - 1));
1129  			if (nToRead > nbyte)
1130  				nToRead = nbyte;
1131  
1132  			/* Tricky bit...
1133  			 * Need to reverify object in case the device was
1134  			 * unmounted in another thread.
1135  			 */
1136  			obj = yaffsfs_HandleToObject(handle);
1137  			if (!obj)
1138  				nRead = 0;
1139  			else
1140  				nRead = yaffs_file_rd(obj, buf, pos, nToRead);
1141  
1142  			if (nRead > 0) {
1143  				totalRead += nRead;
1144  				pos += nRead;
1145  				buf += nRead;
1146  			}
1147  
1148  			if (nRead == nToRead)
1149  				nbyte -= nRead;
1150  			else
1151  				nbyte = 0;	/* no more to read */
1152  
1153  			if (nbyte > 0) {
1154  				yaffsfs_Unlock();
1155  				yaffsfs_Lock();
1156  			}
1157  
1158  		}
1159  
1160  		yaffsfs_PutHandle(handle);
1161  
1162  		if (!isPread) {
1163  			if (totalRead >= 0)
1164  				fd->position = startPos + totalRead;
1165  			else
1166  				yaffsfs_SetError(-EINVAL);
1167  		}
1168  
1169  	}
1170  
1171  	yaffsfs_Unlock();
1172  
1173  	return (totalRead >= 0) ? totalRead : -1;
1174  
1175  }
1176  
1177  int yaffs_read(int handle, void *buf, unsigned int nbyte)
1178  {
1179  	return yaffsfs_do_read(handle, buf, nbyte, 0, 0);
1180  }
1181  
1182  int yaffs_pread(int handle, void *buf, unsigned int nbyte, loff_t offset)
1183  {
1184  	return yaffsfs_do_read(handle, buf, nbyte, 1, offset);
1185  }
1186  
1187  int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte,
1188  		     int isPwrite, loff_t offset)
1189  {
1190  	struct yaffsfs_FileDes *fd = NULL;
1191  	struct yaffs_obj *obj = NULL;
1192  	loff_t pos = 0;
1193  	loff_t startPos = 0;
1194  	loff_t endPos;
1195  	int nWritten = 0;
1196  	int totalWritten = 0;
1197  	int write_trhrough = 0;
1198  	int nToWrite = 0;
1199  	const u8 *buf = (const u8 *)vbuf;
1200  
1201  	if (!vbuf) {
1202  		yaffsfs_SetError(-EFAULT);
1203  		return -1;
1204  	}
1205  
1206  	yaffsfs_Lock();
1207  	fd = yaffsfs_HandleToFileDes(handle);
1208  	obj = yaffsfs_HandleToObject(handle);
1209  
1210  	if (!fd || !obj) {
1211  		/* bad handle */
1212  		yaffsfs_SetError(-EBADF);
1213  		totalWritten = -1;
1214  	} else if (!fd->writing) {
1215  		yaffsfs_SetError(-EINVAL);
1216  		totalWritten = -1;
1217  	} else if (obj->my_dev->read_only) {
1218  		yaffsfs_SetError(-EROFS);
1219  		totalWritten = -1;
1220  	} else {
1221  		if (fd->append)
1222  			startPos = yaffs_get_obj_length(obj);
1223  		else if (isPwrite)
1224  			startPos = offset;
1225  		else
1226  			startPos = fd->position;
1227  
1228  		yaffsfs_GetHandle(handle);
1229  		pos = startPos;
1230  		endPos = pos + nbyte;
1231  
1232  		if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
1233  		    nbyte > YAFFS_MAX_FILE_SIZE ||
1234  		    endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
1235  			totalWritten = -1;
1236  			nbyte = 0;
1237  		}
1238  
1239  		while (nbyte > 0) {
1240  
1241  			nToWrite = YAFFSFS_RW_SIZE -
1242  			    (pos & (YAFFSFS_RW_SIZE - 1));
1243  			if (nToWrite > nbyte)
1244  				nToWrite = nbyte;
1245  
1246  			/* Tricky bit...
1247  			 * Need to reverify object in case the device was
1248  			 * remounted or unmounted in another thread.
1249  			 */
1250  			obj = yaffsfs_HandleToObject(handle);
1251  			if (!obj || obj->my_dev->read_only)
1252  				nWritten = 0;
1253  			else
1254  				nWritten =
1255  				    yaffs_wr_file(obj, buf, pos, nToWrite,
1256  						  write_trhrough);
1257  			if (nWritten > 0) {
1258  				totalWritten += nWritten;
1259  				pos += nWritten;
1260  				buf += nWritten;
1261  			}
1262  
1263  			if (nWritten == nToWrite)
1264  				nbyte -= nToWrite;
1265  			else
1266  				nbyte = 0;
1267  
1268  			if (nWritten < 1 && totalWritten < 1) {
1269  				yaffsfs_SetError(-ENOSPC);
1270  				totalWritten = -1;
1271  			}
1272  
1273  			if (nbyte > 0) {
1274  				yaffsfs_Unlock();
1275  				yaffsfs_Lock();
1276  			}
1277  		}
1278  
1279  		yaffsfs_PutHandle(handle);
1280  
1281  		if (!isPwrite) {
1282  			if (totalWritten > 0)
1283  				fd->position = startPos + totalWritten;
1284  			else
1285  				yaffsfs_SetError(-EINVAL);
1286  		}
1287  	}
1288  
1289  	yaffsfs_Unlock();
1290  
1291  	return (totalWritten >= 0) ? totalWritten : -1;
1292  }
1293  
1294  int yaffs_write(int fd, const void *buf, unsigned int nbyte)
1295  {
1296  	return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
1297  }
1298  
1299  int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, loff_t offset)
1300  {
1301  	return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
1302  }
1303  
1304  int yaffs_truncate(const YCHAR *path, loff_t new_size)
1305  {
1306  	struct yaffs_obj *obj = NULL;
1307  	struct yaffs_obj *dir = NULL;
1308  	int result = YAFFS_FAIL;
1309  	int notDir = 0;
1310  	int loop = 0;
1311  
1312  	if (!path) {
1313  		yaffsfs_SetError(-EFAULT);
1314  		return -1;
1315  	}
1316  
1317  	if (yaffsfs_CheckPath(path) < 0) {
1318  		yaffsfs_SetError(-ENAMETOOLONG);
1319  		return -1;
1320  	}
1321  
1322  	yaffsfs_Lock();
1323  
1324  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
1325  	obj = yaffsfs_FollowLink(obj, 0, &loop);
1326  
1327  	if (!dir && notDir)
1328  		yaffsfs_SetError(-ENOTDIR);
1329  	else if (loop)
1330  		yaffsfs_SetError(-ELOOP);
1331  	else if (!dir || !obj)
1332  		yaffsfs_SetError(-ENOENT);
1333  	else if (obj->my_dev->read_only)
1334  		yaffsfs_SetError(-EROFS);
1335  	else if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
1336  		yaffsfs_SetError(-EISDIR);
1337  	else if (obj->my_dev->read_only)
1338  		yaffsfs_SetError(-EROFS);
1339  	else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1340  		yaffsfs_SetError(-EINVAL);
1341  	else
1342  		result = yaffs_resize_file(obj, new_size);
1343  
1344  	yaffsfs_Unlock();
1345  
1346  	return (result) ? 0 : -1;
1347  }
1348  
1349  int yaffs_ftruncate(int handle, loff_t new_size)
1350  {
1351  	struct yaffsfs_FileDes *fd = NULL;
1352  	struct yaffs_obj *obj = NULL;
1353  	int result = 0;
1354  
1355  	yaffsfs_Lock();
1356  	fd = yaffsfs_HandleToFileDes(handle);
1357  	obj = yaffsfs_HandleToObject(handle);
1358  
1359  	if (!fd || !obj)
1360  		/* bad handle */
1361  		yaffsfs_SetError(-EBADF);
1362  	else if (!fd->writing)
1363  		yaffsfs_SetError(-EINVAL);
1364  	else if (obj->my_dev->read_only)
1365  		yaffsfs_SetError(-EROFS);
1366  	else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1367  		yaffsfs_SetError(-EINVAL);
1368  	else
1369  		/* resize the file */
1370  		result = yaffs_resize_file(obj, new_size);
1371  	yaffsfs_Unlock();
1372  
1373  	return (result) ? 0 : -1;
1374  
1375  }
1376  
1377  loff_t yaffs_lseek(int handle, loff_t offset, int whence)
1378  {
1379  	struct yaffsfs_FileDes *fd = NULL;
1380  	struct yaffs_obj *obj = NULL;
1381  	loff_t pos = -1;
1382  	loff_t fSize = -1;
1383  
1384  	yaffsfs_Lock();
1385  	fd = yaffsfs_HandleToFileDes(handle);
1386  	obj = yaffsfs_HandleToObject(handle);
1387  
1388  	if (!fd || !obj)
1389  		yaffsfs_SetError(-EBADF);
1390  	else if (offset > YAFFS_MAX_FILE_SIZE)
1391  		yaffsfs_SetError(-EINVAL);
1392  	else {
1393  		if (whence == SEEK_SET) {
1394  			if (offset >= 0)
1395  				pos = offset;
1396  		} else if (whence == SEEK_CUR) {
1397  			if ((fd->position + offset) >= 0)
1398  				pos = (fd->position + offset);
1399  		} else if (whence == SEEK_END) {
1400  			fSize = yaffs_get_obj_length(obj);
1401  			if (fSize >= 0 && (fSize + offset) >= 0)
1402  				pos = fSize + offset;
1403  		}
1404  
1405  		if (pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE)
1406  			fd->position = pos;
1407  		else {
1408  			yaffsfs_SetError(-EINVAL);
1409  			pos = -1;
1410  		}
1411  	}
1412  
1413  	yaffsfs_Unlock();
1414  
1415  	return pos;
1416  }
1417  
1418  int yaffsfs_DoUnlink(const YCHAR *path, int isDirectory)
1419  {
1420  	struct yaffs_obj *dir = NULL;
1421  	struct yaffs_obj *obj = NULL;
1422  	YCHAR *name;
1423  	int result = YAFFS_FAIL;
1424  	int notDir = 0;
1425  	int loop = 0;
1426  
1427  	if (!path) {
1428  		yaffsfs_SetError(-EFAULT);
1429  		return -1;
1430  	}
1431  
1432  	if (yaffsfs_CheckPath(path) < 0) {
1433  		yaffsfs_SetError(-ENAMETOOLONG);
1434  		return -1;
1435  	}
1436  
1437  	yaffsfs_Lock();
1438  
1439  	obj = yaffsfs_FindObject(NULL, path, 0, 0, NULL, NULL, NULL);
1440  	dir = yaffsfs_FindDirectory(NULL, path, &name, 0, &notDir, &loop);
1441  
1442  	if (!dir && notDir)
1443  		yaffsfs_SetError(-ENOTDIR);
1444  	else if (loop)
1445  		yaffsfs_SetError(-ELOOP);
1446  	else if (!dir)
1447  		yaffsfs_SetError(-ENOENT);
1448  	else if (yaffs_strncmp(name, _Y("."), 2) == 0)
1449  		yaffsfs_SetError(-EINVAL);
1450  	else if (!obj)
1451  		yaffsfs_SetError(-ENOENT);
1452  	else if (obj->my_dev->read_only)
1453  		yaffsfs_SetError(-EROFS);
1454  	else if (!isDirectory &&
1455  		 obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1456  		yaffsfs_SetError(-EISDIR);
1457  	else if (isDirectory &&
1458  		 obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1459  		yaffsfs_SetError(-ENOTDIR);
1460  	else if (isDirectory && obj == obj->my_dev->root_dir)
1461  		yaffsfs_SetError(-EBUSY);	/* Can't rmdir a root */
1462  	else {
1463  		result = yaffs_unlinker(dir, name);
1464  
1465  		if (result == YAFFS_FAIL && isDirectory)
1466  			yaffsfs_SetError(-ENOTEMPTY);
1467  	}
1468  
1469  	yaffsfs_Unlock();
1470  
1471  	return (result == YAFFS_FAIL) ? -1 : 0;
1472  }
1473  
1474  int yaffs_unlink(const YCHAR *path)
1475  {
1476  	return yaffsfs_DoUnlink(path, 0);
1477  }
1478  
1479  int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1480  {
1481  	struct yaffs_obj *olddir = NULL;
1482  	struct yaffs_obj *newdir = NULL;
1483  	struct yaffs_obj *obj = NULL;
1484  	struct yaffs_obj *newobj = NULL;
1485  	YCHAR *oldname;
1486  	YCHAR *newname;
1487  	int result = YAFFS_FAIL;
1488  	int rename_allowed = 1;
1489  	int notOldDir = 0;
1490  	int notNewDir = 0;
1491  	int oldLoop = 0;
1492  	int newLoop = 0;
1493  
1494  	YCHAR *alt_newpath = NULL;
1495  
1496  	if (!oldPath || !newPath) {
1497  		yaffsfs_SetError(-EFAULT);
1498  		return -1;
1499  	}
1500  
1501  	if (yaffsfs_CheckPath(oldPath) < 0 || yaffsfs_CheckPath(newPath) < 0) {
1502  		yaffsfs_SetError(-ENAMETOOLONG);
1503  		return -1;
1504  	}
1505  
1506  	if (yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0) {
1507  		yaffsfs_SetError(-ENOMEM);
1508  		return -1;
1509  	}
1510  	if (alt_newpath)
1511  		newPath = alt_newpath;
1512  
1513  	yaffsfs_Lock();
1514  
1515  	olddir = yaffsfs_FindDirectory(NULL, oldPath, &oldname, 0,
1516  				       &notOldDir, &oldLoop);
1517  	newdir = yaffsfs_FindDirectory(NULL, newPath, &newname, 0,
1518  				       &notNewDir, &newLoop);
1519  	obj = yaffsfs_FindObject(NULL, oldPath, 0, 0, NULL, NULL, NULL);
1520  	newobj = yaffsfs_FindObject(NULL, newPath, 0, 0, NULL, NULL, NULL);
1521  
1522  	/* If the object being renamed is a directory and the
1523  	 * path ended with a "/" then the olddir == obj.
1524  	 * We pass through NULL for the old name to tell the lower layers
1525  	 * to use olddir as the object.
1526  	 */
1527  
1528  	if (olddir == obj)
1529  		oldname = NULL;
1530  
1531  	if ((!olddir && notOldDir) || (!newdir && notNewDir)) {
1532  		yaffsfs_SetError(-ENOTDIR);
1533  		rename_allowed = 0;
1534  	} else if (oldLoop || newLoop) {
1535  		yaffsfs_SetError(-ELOOP);
1536  		rename_allowed = 0;
1537  	} else if (olddir && oldname &&
1538  			yaffs_strncmp(oldname, _Y("."), 2) == 0) {
1539  		yaffsfs_SetError(-EINVAL);
1540  		rename_allowed = 0;
1541  	} else if (!olddir || !newdir || !obj) {
1542  		yaffsfs_SetError(-ENOENT);
1543  		rename_allowed = 0;
1544  	} else if (obj->my_dev->read_only) {
1545  		yaffsfs_SetError(-EROFS);
1546  		rename_allowed = 0;
1547  	} else if (yaffs_is_non_empty_dir(newobj)) {
1548  		yaffsfs_SetError(-ENOTEMPTY);
1549  		rename_allowed = 0;
1550  	} else if (olddir->my_dev != newdir->my_dev) {
1551  		/* Rename must be on same device */
1552  		yaffsfs_SetError(-EXDEV);
1553  		rename_allowed = 0;
1554  	} else if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1555  		/*
1556  		 * It is a directory, check that it is not being renamed to
1557  		 * being its own decendent.
1558  		 * Do this by tracing from the new directory back to the root,
1559  		 * checking for obj
1560  		 */
1561  
1562  		struct yaffs_obj *xx = newdir;
1563  
1564  		while (rename_allowed && xx) {
1565  			if (xx == obj)
1566  				rename_allowed = 0;
1567  			xx = xx->parent;
1568  		}
1569  		if (!rename_allowed)
1570  			yaffsfs_SetError(-EINVAL);
1571  	}
1572  
1573  	if (rename_allowed)
1574  		result = yaffs_rename_obj(olddir, oldname, newdir, newname);
1575  
1576  	yaffsfs_Unlock();
1577  
1578  	kfree(alt_newpath);
1579  
1580  	return (result == YAFFS_FAIL) ? -1 : 0;
1581  }
1582  
1583  static int yaffsfs_DoStat(struct yaffs_obj *obj, struct yaffs_stat *buf)
1584  {
1585  	int retVal = -1;
1586  
1587  	obj = yaffs_get_equivalent_obj(obj);
1588  
1589  	if (obj && buf) {
1590  		buf->st_dev = (int)obj->my_dev->os_context;
1591  		buf->st_ino = obj->obj_id;
1592  		buf->st_mode = obj->yst_mode & ~S_IFMT;
1593  
1594  		if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1595  			buf->st_mode |= S_IFDIR;
1596  		else if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1597  			buf->st_mode |= S_IFLNK;
1598  		else if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1599  			buf->st_mode |= S_IFREG;
1600  
1601  		buf->st_nlink = yaffs_get_obj_link_count(obj);
1602  		buf->st_uid = 0;
1603  		buf->st_gid = 0;
1604  		buf->st_rdev = obj->yst_rdev;
1605  		buf->st_size = yaffs_get_obj_length(obj);
1606  		buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
1607  		buf->st_blocks = lldiv(buf->st_size + buf->st_blksize - 1,
1608  		    buf->st_blksize);
1609  #if CONFIG_YAFFS_WINCE
1610  		buf->yst_wince_atime[0] = obj->win_atime[0];
1611  		buf->yst_wince_atime[1] = obj->win_atime[1];
1612  		buf->yst_wince_ctime[0] = obj->win_ctime[0];
1613  		buf->yst_wince_ctime[1] = obj->win_ctime[1];
1614  		buf->yst_wince_mtime[0] = obj->win_mtime[0];
1615  		buf->yst_wince_mtime[1] = obj->win_mtime[1];
1616  #else
1617  		buf->yst_atime = obj->yst_atime;
1618  		buf->yst_ctime = obj->yst_ctime;
1619  		buf->yst_mtime = obj->yst_mtime;
1620  #endif
1621  		retVal = 0;
1622  	}
1623  	return retVal;
1624  }
1625  
1626  static int yaffsfs_DoStatOrLStat(const YCHAR *path,
1627  				 struct yaffs_stat *buf, int doLStat)
1628  {
1629  	struct yaffs_obj *obj = NULL;
1630  	struct yaffs_obj *dir = NULL;
1631  	int retVal = -1;
1632  	int notDir = 0;
1633  	int loop = 0;
1634  
1635  	if (!path || !buf) {
1636  		yaffsfs_SetError(-EFAULT);
1637  		return -1;
1638  	}
1639  
1640  	if (yaffsfs_CheckPath(path) < 0) {
1641  		yaffsfs_SetError(-ENAMETOOLONG);
1642  		return -1;
1643  	}
1644  
1645  	yaffsfs_Lock();
1646  
1647  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
1648  
1649  	if (!doLStat && obj)
1650  		obj = yaffsfs_FollowLink(obj, 0, &loop);
1651  
1652  	if (!dir && notDir)
1653  		yaffsfs_SetError(-ENOTDIR);
1654  	else if (loop)
1655  		yaffsfs_SetError(-ELOOP);
1656  	else if (!dir || !obj)
1657  		yaffsfs_SetError(-ENOENT);
1658  	else
1659  		retVal = yaffsfs_DoStat(obj, buf);
1660  
1661  	yaffsfs_Unlock();
1662  
1663  	return retVal;
1664  
1665  }
1666  
1667  int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1668  {
1669  	return yaffsfs_DoStatOrLStat(path, buf, 0);
1670  }
1671  
1672  int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1673  {
1674  	return yaffsfs_DoStatOrLStat(path, buf, 1);
1675  }
1676  
1677  int yaffs_fstat(int fd, struct yaffs_stat *buf)
1678  {
1679  	struct yaffs_obj *obj;
1680  
1681  	int retVal = -1;
1682  
1683  	if (!buf) {
1684  		yaffsfs_SetError(-EFAULT);
1685  		return -1;
1686  	}
1687  
1688  	yaffsfs_Lock();
1689  	obj = yaffsfs_HandleToObject(fd);
1690  
1691  	if (obj)
1692  		retVal = yaffsfs_DoStat(obj, buf);
1693  	else
1694  		/* bad handle */
1695  		yaffsfs_SetError(-EBADF);
1696  
1697  	yaffsfs_Unlock();
1698  
1699  	return retVal;
1700  }
1701  
1702  static int yaffsfs_DoUtime(struct yaffs_obj *obj,
1703  			   const struct yaffs_utimbuf *buf)
1704  {
1705  	int retVal = -1;
1706  	int result;
1707  
1708  	struct yaffs_utimbuf local;
1709  
1710  	obj = yaffs_get_equivalent_obj(obj);
1711  
1712  	if (obj && obj->my_dev->read_only) {
1713  		yaffsfs_SetError(-EROFS);
1714  		return -1;
1715  	}
1716  
1717  	if (!buf) {
1718  		local.actime = Y_CURRENT_TIME;
1719  		local.modtime = local.actime;
1720  		buf = &local;
1721  	}
1722  
1723  	if (obj) {
1724  		obj->yst_atime = buf->actime;
1725  		obj->yst_mtime = buf->modtime;
1726  		obj->dirty = 1;
1727  		result = yaffs_flush_file(obj, 0, 0);
1728  		retVal = result == YAFFS_OK ? 0 : -1;
1729  	}
1730  
1731  	return retVal;
1732  }
1733  
1734  int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf)
1735  {
1736  	struct yaffs_obj *obj = NULL;
1737  	struct yaffs_obj *dir = NULL;
1738  	int retVal = -1;
1739  	int notDir = 0;
1740  	int loop = 0;
1741  
1742  	if (!path) {
1743  		yaffsfs_SetError(-EFAULT);
1744  		return -1;
1745  	}
1746  
1747  	if (yaffsfs_CheckPath(path) < 0) {
1748  		yaffsfs_SetError(-ENAMETOOLONG);
1749  		return -1;
1750  	}
1751  
1752  	yaffsfs_Lock();
1753  
1754  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
1755  
1756  	if (!dir && notDir)
1757  		yaffsfs_SetError(-ENOTDIR);
1758  	else if (loop)
1759  		yaffsfs_SetError(-ELOOP);
1760  	else if (!dir || !obj)
1761  		yaffsfs_SetError(-ENOENT);
1762  	else
1763  		retVal = yaffsfs_DoUtime(obj, buf);
1764  
1765  	yaffsfs_Unlock();
1766  
1767  	return retVal;
1768  
1769  }
1770  
1771  int yaffs_futime(int fd, const struct yaffs_utimbuf *buf)
1772  {
1773  	struct yaffs_obj *obj;
1774  
1775  	int retVal = -1;
1776  
1777  	yaffsfs_Lock();
1778  	obj = yaffsfs_HandleToObject(fd);
1779  
1780  	if (obj)
1781  		retVal = yaffsfs_DoUtime(obj, buf);
1782  	else
1783  		/* bad handle */
1784  		yaffsfs_SetError(-EBADF);
1785  
1786  	yaffsfs_Unlock();
1787  
1788  	return retVal;
1789  }
1790  
1791  #ifndef CONFIG_YAFFS_WINCE
1792  /* xattrib functions */
1793  
1794  static int yaffs_do_setxattr(const YCHAR *path, const char *name,
1795  			     const void *data, int size, int flags, int follow)
1796  {
1797  	struct yaffs_obj *obj;
1798  	struct yaffs_obj *dir;
1799  	int notDir = 0;
1800  	int loop = 0;
1801  
1802  	int retVal = -1;
1803  
1804  	if (!path || !name || !data) {
1805  		yaffsfs_SetError(-EFAULT);
1806  		return -1;
1807  	}
1808  
1809  	if (yaffsfs_CheckPath(path) < 0) {
1810  		yaffsfs_SetError(-ENAMETOOLONG);
1811  		return -1;
1812  	}
1813  
1814  	yaffsfs_Lock();
1815  
1816  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
1817  
1818  	if (follow)
1819  		obj = yaffsfs_FollowLink(obj, 0, &loop);
1820  
1821  	if (!dir && notDir)
1822  		yaffsfs_SetError(-ENOTDIR);
1823  	else if (loop)
1824  		yaffsfs_SetError(-ELOOP);
1825  	else if (!dir || !obj)
1826  		yaffsfs_SetError(-ENOENT);
1827  	else {
1828  		retVal = yaffs_set_xattrib(obj, name, data, size, flags);
1829  		if (retVal < 0) {
1830  			yaffsfs_SetError(retVal);
1831  			retVal = -1;
1832  		}
1833  	}
1834  
1835  	yaffsfs_Unlock();
1836  
1837  	return retVal;
1838  
1839  }
1840  
1841  int yaffs_setxattr(const YCHAR *path, const char *name,
1842  		   const void *data, int size, int flags)
1843  {
1844  	return yaffs_do_setxattr(path, name, data, size, flags, 1);
1845  }
1846  
1847  int yaffs_lsetxattr(const YCHAR *path, const char *name,
1848  		    const void *data, int size, int flags)
1849  {
1850  	return yaffs_do_setxattr(path, name, data, size, flags, 0);
1851  }
1852  
1853  int yaffs_fsetxattr(int fd, const char *name,
1854  		    const void *data, int size, int flags)
1855  {
1856  	struct yaffs_obj *obj;
1857  
1858  	int retVal = -1;
1859  
1860  	if (!name || !data) {
1861  		yaffsfs_SetError(-EFAULT);
1862  		return -1;
1863  	}
1864  
1865  	yaffsfs_Lock();
1866  	obj = yaffsfs_HandleToObject(fd);
1867  
1868  	if (!obj)
1869  		yaffsfs_SetError(-EBADF);
1870  	else {
1871  		retVal = yaffs_set_xattrib(obj, name, data, size, flags);
1872  		if (retVal < 0) {
1873  			yaffsfs_SetError(retVal);
1874  			retVal = -1;
1875  		}
1876  	}
1877  
1878  	yaffsfs_Unlock();
1879  
1880  	return retVal;
1881  }
1882  
1883  static int yaffs_do_getxattr(const YCHAR *path, const char *name,
1884  			     void *data, int size, int follow)
1885  {
1886  	struct yaffs_obj *obj;
1887  	struct yaffs_obj *dir;
1888  	int retVal = -1;
1889  	int notDir = 0;
1890  	int loop = 0;
1891  
1892  	if (!path || !name || !data) {
1893  		yaffsfs_SetError(-EFAULT);
1894  		return -1;
1895  	}
1896  
1897  	if (yaffsfs_CheckPath(path) < 0) {
1898  		yaffsfs_SetError(-ENAMETOOLONG);
1899  		return -1;
1900  	}
1901  
1902  	yaffsfs_Lock();
1903  
1904  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
1905  
1906  	if (follow)
1907  		obj = yaffsfs_FollowLink(obj, 0, &loop);
1908  
1909  	if (!dir && notDir)
1910  		yaffsfs_SetError(-ENOTDIR);
1911  	else if (loop)
1912  		yaffsfs_SetError(-ELOOP);
1913  	else if (!dir || !obj)
1914  		yaffsfs_SetError(-ENOENT);
1915  	else {
1916  		retVal = yaffs_get_xattrib(obj, name, data, size);
1917  		if (retVal < 0) {
1918  			yaffsfs_SetError(retVal);
1919  			retVal = -1;
1920  		}
1921  	}
1922  	yaffsfs_Unlock();
1923  
1924  	return retVal;
1925  
1926  }
1927  
1928  int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1929  {
1930  	return yaffs_do_getxattr(path, name, data, size, 1);
1931  }
1932  
1933  int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1934  {
1935  	return yaffs_do_getxattr(path, name, data, size, 0);
1936  }
1937  
1938  int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1939  {
1940  	struct yaffs_obj *obj;
1941  
1942  	int retVal = -1;
1943  
1944  	if (!name || !data) {
1945  		yaffsfs_SetError(-EFAULT);
1946  		return -1;
1947  	}
1948  
1949  	yaffsfs_Lock();
1950  	obj = yaffsfs_HandleToObject(fd);
1951  
1952  	if (obj) {
1953  		retVal = yaffs_get_xattrib(obj, name, data, size);
1954  		if (retVal < 0) {
1955  			yaffsfs_SetError(retVal);
1956  			retVal = -1;
1957  		}
1958  	} else
1959  		/* bad handle */
1960  		yaffsfs_SetError(-EBADF);
1961  
1962  	yaffsfs_Unlock();
1963  
1964  	return retVal;
1965  }
1966  
1967  static int yaffs_do_listxattr(const YCHAR *path, char *data,
1968  			      int size, int follow)
1969  {
1970  	struct yaffs_obj *obj = NULL;
1971  	struct yaffs_obj *dir = NULL;
1972  	int retVal = -1;
1973  	int notDir = 0;
1974  	int loop = 0;
1975  
1976  	if (!path || !data) {
1977  		yaffsfs_SetError(-EFAULT);
1978  		return -1;
1979  	}
1980  
1981  	if (yaffsfs_CheckPath(path) < 0) {
1982  		yaffsfs_SetError(-ENAMETOOLONG);
1983  		return -1;
1984  	}
1985  
1986  	yaffsfs_Lock();
1987  
1988  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
1989  
1990  	if (follow)
1991  		obj = yaffsfs_FollowLink(obj, 0, &loop);
1992  
1993  	if (!dir && notDir)
1994  		yaffsfs_SetError(-ENOTDIR);
1995  	else if (loop)
1996  		yaffsfs_SetError(-ELOOP);
1997  	else if (!dir || !obj)
1998  		yaffsfs_SetError(-ENOENT);
1999  	else {
2000  		retVal = yaffs_list_xattrib(obj, data, size);
2001  		if (retVal < 0) {
2002  			yaffsfs_SetError(retVal);
2003  			retVal = -1;
2004  		}
2005  	}
2006  
2007  	yaffsfs_Unlock();
2008  
2009  	return retVal;
2010  
2011  }
2012  
2013  int yaffs_listxattr(const YCHAR *path, char *data, int size)
2014  {
2015  	return yaffs_do_listxattr(path, data, size, 1);
2016  }
2017  
2018  int yaffs_llistxattr(const YCHAR *path, char *data, int size)
2019  {
2020  	return yaffs_do_listxattr(path, data, size, 0);
2021  }
2022  
2023  int yaffs_flistxattr(int fd, char *data, int size)
2024  {
2025  	struct yaffs_obj *obj;
2026  
2027  	int retVal = -1;
2028  
2029  	if (!data) {
2030  		yaffsfs_SetError(-EFAULT);
2031  		return -1;
2032  	}
2033  
2034  	yaffsfs_Lock();
2035  	obj = yaffsfs_HandleToObject(fd);
2036  
2037  	if (obj) {
2038  		retVal = yaffs_list_xattrib(obj, data, size);
2039  		if (retVal < 0) {
2040  			yaffsfs_SetError(retVal);
2041  			retVal = -1;
2042  		}
2043  	} else
2044  		/* bad handle */
2045  		yaffsfs_SetError(-EBADF);
2046  
2047  	yaffsfs_Unlock();
2048  
2049  	return retVal;
2050  }
2051  
2052  static int yaffs_do_removexattr(const YCHAR *path, const char *name,
2053  				int follow)
2054  {
2055  	struct yaffs_obj *obj = NULL;
2056  	struct yaffs_obj *dir = NULL;
2057  	int notDir = 0;
2058  	int loop = 0;
2059  	int retVal = -1;
2060  
2061  	if (!path || !name) {
2062  		yaffsfs_SetError(-EFAULT);
2063  		return -1;
2064  	}
2065  
2066  	if (yaffsfs_CheckPath(path) < 0) {
2067  		yaffsfs_SetError(-ENAMETOOLONG);
2068  		return -1;
2069  	}
2070  
2071  	yaffsfs_Lock();
2072  
2073  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
2074  
2075  	if (follow)
2076  		obj = yaffsfs_FollowLink(obj, 0, &loop);
2077  
2078  	if (!dir && notDir)
2079  		yaffsfs_SetError(-ENOTDIR);
2080  	else if (loop)
2081  		yaffsfs_SetError(-ELOOP);
2082  	else if (!dir || !obj)
2083  		yaffsfs_SetError(-ENOENT);
2084  	else {
2085  		retVal = yaffs_remove_xattrib(obj, name);
2086  		if (retVal < 0) {
2087  			yaffsfs_SetError(retVal);
2088  			retVal = -1;
2089  		}
2090  	}
2091  
2092  	yaffsfs_Unlock();
2093  
2094  	return retVal;
2095  
2096  }
2097  
2098  int yaffs_removexattr(const YCHAR *path, const char *name)
2099  {
2100  	return yaffs_do_removexattr(path, name, 1);
2101  }
2102  
2103  int yaffs_lremovexattr(const YCHAR *path, const char *name)
2104  {
2105  	return yaffs_do_removexattr(path, name, 0);
2106  }
2107  
2108  int yaffs_fremovexattr(int fd, const char *name)
2109  {
2110  	struct yaffs_obj *obj;
2111  
2112  	int retVal = -1;
2113  
2114  	if (!name) {
2115  		yaffsfs_SetError(-EFAULT);
2116  		return -1;
2117  	}
2118  
2119  	yaffsfs_Lock();
2120  	obj = yaffsfs_HandleToObject(fd);
2121  
2122  	if (obj) {
2123  		retVal = yaffs_remove_xattrib(obj, name);
2124  		if (retVal < 0) {
2125  			yaffsfs_SetError(retVal);
2126  			retVal = -1;
2127  		}
2128  	} else
2129  		/* bad handle */
2130  		yaffsfs_SetError(-EBADF);
2131  
2132  	yaffsfs_Unlock();
2133  
2134  	return retVal;
2135  }
2136  #endif
2137  
2138  #ifdef CONFIG_YAFFS_WINCE
2139  int yaffs_get_wince_times(int fd, unsigned *wctime,
2140  			  unsigned *watime, unsigned *wmtime)
2141  {
2142  	struct yaffs_obj *obj;
2143  
2144  	int retVal = -1;
2145  
2146  	yaffsfs_Lock();
2147  	obj = yaffsfs_HandleToObject(fd);
2148  
2149  	if (obj) {
2150  
2151  		if (wctime) {
2152  			wctime[0] = obj->win_ctime[0];
2153  			wctime[1] = obj->win_ctime[1];
2154  		}
2155  		if (watime) {
2156  			watime[0] = obj->win_atime[0];
2157  			watime[1] = obj->win_atime[1];
2158  		}
2159  		if (wmtime) {
2160  			wmtime[0] = obj->win_mtime[0];
2161  			wmtime[1] = obj->win_mtime[1];
2162  		}
2163  
2164  		retVal = 0;
2165  	} else
2166  		/*  bad handle */
2167  		yaffsfs_SetError(-EBADF);
2168  
2169  	yaffsfs_Unlock();
2170  
2171  	return retVal;
2172  }
2173  
2174  int yaffs_set_wince_times(int fd,
2175  			  const unsigned *wctime,
2176  			  const unsigned *watime, const unsigned *wmtime)
2177  {
2178  	struct yaffs_obj *obj;
2179  	int result;
2180  	int retVal = -1;
2181  
2182  	yaffsfs_Lock();
2183  	obj = yaffsfs_HandleToObject(fd);
2184  
2185  	if (obj) {
2186  
2187  		if (wctime) {
2188  			obj->win_ctime[0] = wctime[0];
2189  			obj->win_ctime[1] = wctime[1];
2190  		}
2191  		if (watime) {
2192  			obj->win_atime[0] = watime[0];
2193  			obj->win_atime[1] = watime[1];
2194  		}
2195  		if (wmtime) {
2196  			obj->win_mtime[0] = wmtime[0];
2197  			obj->win_mtime[1] = wmtime[1];
2198  		}
2199  
2200  		obj->dirty = 1;
2201  		result = yaffs_flush_file(obj, 0, 0);
2202  		retVal = 0;
2203  	} else
2204  		/* bad handle */
2205  		yaffsfs_SetError(-EBADF);
2206  
2207  	yaffsfs_Unlock();
2208  
2209  	return retVal;
2210  }
2211  
2212  #endif
2213  
2214  static int yaffsfs_DoChMod(struct yaffs_obj *obj, mode_t mode)
2215  {
2216  	int result = -1;
2217  
2218  	if (obj)
2219  		obj = yaffs_get_equivalent_obj(obj);
2220  
2221  	if (obj) {
2222  		obj->yst_mode = mode;
2223  		obj->dirty = 1;
2224  		result = yaffs_flush_file(obj, 0, 0);
2225  	}
2226  
2227  	return result == YAFFS_OK ? 0 : -1;
2228  }
2229  
2230  int yaffs_access(const YCHAR *path, int amode)
2231  {
2232  	struct yaffs_obj *obj = NULL;
2233  	struct yaffs_obj *dir = NULL;
2234  	int notDir = 0;
2235  	int loop = 0;
2236  	int retval = -1;
2237  
2238  	if (!path) {
2239  		yaffsfs_SetError(-EFAULT);
2240  		return -1;
2241  	}
2242  
2243  	if (yaffsfs_CheckPath(path) < 0) {
2244  		yaffsfs_SetError(-ENAMETOOLONG);
2245  		return -1;
2246  	}
2247  
2248  	if (amode & ~(R_OK | W_OK | X_OK)) {
2249  		yaffsfs_SetError(-EINVAL);
2250  		return -1;
2251  	}
2252  
2253  	yaffsfs_Lock();
2254  
2255  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
2256  	obj = yaffsfs_FollowLink(obj, 0, &loop);
2257  
2258  	if (!dir && notDir)
2259  		yaffsfs_SetError(-ENOTDIR);
2260  	else if (loop)
2261  		yaffsfs_SetError(-ELOOP);
2262  	else if (!dir || !obj)
2263  		yaffsfs_SetError(-ENOENT);
2264  	else if ((amode & W_OK) && obj->my_dev->read_only)
2265  		yaffsfs_SetError(-EROFS);
2266  	else {
2267  		int access_ok = 1;
2268  
2269  		if ((amode & R_OK) && !(obj->yst_mode & S_IREAD))
2270  			access_ok = 0;
2271  		if ((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
2272  			access_ok = 0;
2273  		if ((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
2274  			access_ok = 0;
2275  
2276  		if (!access_ok)
2277  			yaffsfs_SetError(-EACCES);
2278  		else
2279  			retval = 0;
2280  	}
2281  
2282  	yaffsfs_Unlock();
2283  
2284  	return retval;
2285  
2286  }
2287  
2288  int yaffs_chmod(const YCHAR *path, mode_t mode)
2289  {
2290  	struct yaffs_obj *obj = NULL;
2291  	struct yaffs_obj *dir = NULL;
2292  	int retVal = -1;
2293  	int notDir = 0;
2294  	int loop = 0;
2295  
2296  	if (!path) {
2297  		yaffsfs_SetError(-EFAULT);
2298  		return -1;
2299  	}
2300  
2301  	if (yaffsfs_CheckPath(path) < 0) {
2302  		yaffsfs_SetError(-ENAMETOOLONG);
2303  		return -1;
2304  	}
2305  
2306  	if (mode & ~(0777)) {
2307  		yaffsfs_SetError(-EINVAL);
2308  		return -1;
2309  	}
2310  
2311  	yaffsfs_Lock();
2312  
2313  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
2314  	obj = yaffsfs_FollowLink(obj, 0, &loop);
2315  
2316  	if (!dir && notDir)
2317  		yaffsfs_SetError(-ENOTDIR);
2318  	else if (loop)
2319  		yaffsfs_SetError(-ELOOP);
2320  	else if (!dir || !obj)
2321  		yaffsfs_SetError(-ENOENT);
2322  	else if (obj->my_dev->read_only)
2323  		yaffsfs_SetError(-EROFS);
2324  	else
2325  		retVal = yaffsfs_DoChMod(obj, mode);
2326  
2327  	yaffsfs_Unlock();
2328  
2329  	return retVal;
2330  
2331  }
2332  
2333  int yaffs_fchmod(int fd, mode_t mode)
2334  {
2335  	struct yaffs_obj *obj;
2336  	int retVal = -1;
2337  
2338  	if (mode & ~(0777)) {
2339  		yaffsfs_SetError(-EINVAL);
2340  		return -1;
2341  	}
2342  
2343  	yaffsfs_Lock();
2344  	obj = yaffsfs_HandleToObject(fd);
2345  
2346  	if (!obj)
2347  		yaffsfs_SetError(-EBADF);
2348  	else if (obj->my_dev->read_only)
2349  		yaffsfs_SetError(-EROFS);
2350  	else
2351  		retVal = yaffsfs_DoChMod(obj, mode);
2352  
2353  	yaffsfs_Unlock();
2354  
2355  	return retVal;
2356  }
2357  
2358  int yaffs_mkdir(const YCHAR *path, mode_t mode)
2359  {
2360  	struct yaffs_obj *parent = NULL;
2361  	struct yaffs_obj *dir = NULL;
2362  	YCHAR *name;
2363  	YCHAR *alt_path = NULL;
2364  	int retVal = -1;
2365  	int notDir = 0;
2366  	int loop = 0;
2367  
2368  	if (!path) {
2369  		yaffsfs_SetError(-EFAULT);
2370  		return -1;
2371  	}
2372  
2373  	if (yaffsfs_CheckPath(path) < 0) {
2374  		yaffsfs_SetError(-ENAMETOOLONG);
2375  		return -1;
2376  	}
2377  
2378  	if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
2379  		yaffsfs_SetError(-ENOMEM);
2380  		return -1;
2381  	}
2382  	if (alt_path)
2383  		path = alt_path;
2384  
2385  	yaffsfs_Lock();
2386  	parent = yaffsfs_FindDirectory(NULL, path, &name, 0, &notDir, &loop);
2387  	if (!parent && notDir)
2388  		yaffsfs_SetError(-ENOTDIR);
2389  	else if (loop)
2390  		yaffsfs_SetError(-ELOOP);
2391  	else if (!parent)
2392  		yaffsfs_SetError(-ENOENT);
2393  	else if (yaffsfs_TooManyObjects(parent->my_dev))
2394  		yaffsfs_SetError(-ENFILE);
2395  	else if (yaffs_strnlen(name, 5) == 0) {
2396  		/* Trying to make the root itself */
2397  		yaffsfs_SetError(-EEXIST);
2398  	} else if (parent->my_dev->read_only)
2399  		yaffsfs_SetError(-EROFS);
2400  	else {
2401  		dir = yaffs_create_dir(parent, name, mode, 0, 0);
2402  		if (dir)
2403  			retVal = 0;
2404  		else if (yaffs_find_by_name(parent, name))
2405  			yaffsfs_SetError(-EEXIST);	/* name exists */
2406  		else
2407  			yaffsfs_SetError(-ENOSPC);	/* assume no space */
2408  	}
2409  
2410  	yaffsfs_Unlock();
2411  
2412  	kfree(alt_path);
2413  
2414  	return retVal;
2415  }
2416  
2417  int yaffs_rmdir(const YCHAR *path)
2418  {
2419  	int result;
2420  	YCHAR *alt_path;
2421  
2422  	if (!path) {
2423  		yaffsfs_SetError(-EFAULT);
2424  		return -1;
2425  	}
2426  
2427  	if (yaffsfs_CheckPath(path) < 0) {
2428  		yaffsfs_SetError(-ENAMETOOLONG);
2429  		return -1;
2430  	}
2431  
2432  	if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
2433  		yaffsfs_SetError(-ENOMEM);
2434  		return -1;
2435  	}
2436  	if (alt_path)
2437  		path = alt_path;
2438  	result = yaffsfs_DoUnlink(path, 1);
2439  
2440  	kfree(alt_path);
2441  
2442  	return result;
2443  }
2444  
2445  void *yaffs_getdev(const YCHAR *path)
2446  {
2447  	struct yaffs_dev *dev = NULL;
2448  	YCHAR *dummy;
2449  	dev = yaffsfs_FindDevice(path, &dummy);
2450  	return (void *)dev;
2451  }
2452  
2453  int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt)
2454  {
2455  	int retVal = -1;
2456  	int result = YAFFS_FAIL;
2457  	struct yaffs_dev *dev = NULL;
2458  
2459  	if (!path) {
2460  		yaffsfs_SetError(-EFAULT);
2461  		return -1;
2462  	}
2463  
2464  	yaffs_trace(YAFFS_TRACE_MOUNT, "yaffs: Mounting %s", path);
2465  
2466  	if (yaffsfs_CheckPath(path) < 0) {
2467  		yaffsfs_SetError(-ENAMETOOLONG);
2468  		return -1;
2469  	}
2470  
2471  	yaffsfs_Lock();
2472  
2473  	yaffsfs_InitHandles();
2474  
2475  	dev = yaffsfs_FindMountPoint(path);
2476  	if (dev) {
2477  		if (!dev->is_mounted) {
2478  			dev->read_only = read_only ? 1 : 0;
2479  			if (skip_checkpt) {
2480  				u8 skip = dev->param.skip_checkpt_rd;
2481  				dev->param.skip_checkpt_rd = 1;
2482  				result = yaffs_guts_initialise(dev);
2483  				dev->param.skip_checkpt_rd = skip;
2484  			} else {
2485  				result = yaffs_guts_initialise(dev);
2486  			}
2487  
2488  			if (result == YAFFS_FAIL)
2489  				yaffsfs_SetError(-ENOMEM);
2490  			retVal = result ? 0 : -1;
2491  
2492  		} else
2493  			yaffsfs_SetError(-EBUSY);
2494  	} else
2495  		yaffsfs_SetError(-ENODEV);
2496  
2497  	yaffsfs_Unlock();
2498  	return retVal;
2499  
2500  }
2501  
2502  int yaffs_mount2(const YCHAR *path, int readonly)
2503  {
2504  	return yaffs_mount_common(path, readonly, 0);
2505  }
2506  
2507  int yaffs_mount(const YCHAR *path)
2508  {
2509  	return yaffs_mount_common(path, 0, 0);
2510  }
2511  
2512  int yaffs_sync(const YCHAR *path)
2513  {
2514  	int retVal = -1;
2515  	struct yaffs_dev *dev = NULL;
2516  	YCHAR *dummy;
2517  
2518  	if (!path) {
2519  		yaffsfs_SetError(-EFAULT);
2520  		return -1;
2521  	}
2522  
2523  	if (yaffsfs_CheckPath(path) < 0) {
2524  		yaffsfs_SetError(-ENAMETOOLONG);
2525  		return -1;
2526  	}
2527  
2528  	yaffsfs_Lock();
2529  	dev = yaffsfs_FindDevice(path, &dummy);
2530  	if (dev) {
2531  		if (!dev->is_mounted)
2532  			yaffsfs_SetError(-EINVAL);
2533  		else if (dev->read_only)
2534  			yaffsfs_SetError(-EROFS);
2535  		else {
2536  
2537  			yaffs_flush_whole_cache(dev);
2538  			yaffs_checkpoint_save(dev);
2539  			retVal = 0;
2540  
2541  		}
2542  	} else
2543  		yaffsfs_SetError(-ENODEV);
2544  
2545  	yaffsfs_Unlock();
2546  	return retVal;
2547  }
2548  
2549  static int yaffsfs_IsDevBusy(struct yaffs_dev *dev)
2550  {
2551  	int i;
2552  	struct yaffs_obj *obj;
2553  
2554  	for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
2555  		obj = yaffsfs_HandleToObject(i);
2556  		if (obj && obj->my_dev == dev)
2557  			return 1;
2558  	}
2559  	return 0;
2560  }
2561  
2562  int yaffs_remount(const YCHAR *path, int force, int read_only)
2563  {
2564  	int retVal = -1;
2565  	struct yaffs_dev *dev = NULL;
2566  
2567  	if (!path) {
2568  		yaffsfs_SetError(-EFAULT);
2569  		return -1;
2570  	}
2571  
2572  	if (yaffsfs_CheckPath(path) < 0) {
2573  		yaffsfs_SetError(-ENAMETOOLONG);
2574  		return -1;
2575  	}
2576  
2577  	yaffsfs_Lock();
2578  	dev = yaffsfs_FindMountPoint(path);
2579  	if (dev) {
2580  		if (dev->is_mounted) {
2581  			yaffs_flush_whole_cache(dev);
2582  
2583  			if (force || !yaffsfs_IsDevBusy(dev)) {
2584  				if (read_only)
2585  					yaffs_checkpoint_save(dev);
2586  				dev->read_only = read_only ? 1 : 0;
2587  				retVal = 0;
2588  			} else
2589  				yaffsfs_SetError(-EBUSY);
2590  
2591  		} else
2592  			yaffsfs_SetError(-EINVAL);
2593  
2594  	} else
2595  		yaffsfs_SetError(-ENODEV);
2596  
2597  	yaffsfs_Unlock();
2598  	return retVal;
2599  
2600  }
2601  
2602  int yaffs_unmount2(const YCHAR *path, int force)
2603  {
2604  	int retVal = -1;
2605  	struct yaffs_dev *dev = NULL;
2606  
2607  	if (!path) {
2608  		yaffsfs_SetError(-EFAULT);
2609  		return -1;
2610  	}
2611  
2612  	if (yaffsfs_CheckPath(path) < 0) {
2613  		yaffsfs_SetError(-ENAMETOOLONG);
2614  		return -1;
2615  	}
2616  
2617  	yaffsfs_Lock();
2618  	dev = yaffsfs_FindMountPoint(path);
2619  	if (dev) {
2620  		if (dev->is_mounted) {
2621  			int inUse;
2622  			yaffs_flush_whole_cache(dev);
2623  			yaffs_checkpoint_save(dev);
2624  			inUse = yaffsfs_IsDevBusy(dev);
2625  			if (!inUse || force) {
2626  				if (inUse)
2627  					yaffsfs_BreakDeviceHandles(dev);
2628  				yaffs_deinitialise(dev);
2629  
2630  				retVal = 0;
2631  			} else
2632  				yaffsfs_SetError(-EBUSY);
2633  
2634  		} else
2635  			yaffsfs_SetError(-EINVAL);
2636  
2637  	} else
2638  		yaffsfs_SetError(-ENODEV);
2639  
2640  	yaffsfs_Unlock();
2641  	return retVal;
2642  
2643  }
2644  
2645  int yaffs_unmount(const YCHAR *path)
2646  {
2647  	return yaffs_unmount2(path, 0);
2648  }
2649  
2650  loff_t yaffs_freespace(const YCHAR *path)
2651  {
2652  	loff_t retVal = -1;
2653  	struct yaffs_dev *dev = NULL;
2654  	YCHAR *dummy;
2655  
2656  	if (!path) {
2657  		yaffsfs_SetError(-EFAULT);
2658  		return -1;
2659  	}
2660  
2661  	if (yaffsfs_CheckPath(path) < 0) {
2662  		yaffsfs_SetError(-ENAMETOOLONG);
2663  		return -1;
2664  	}
2665  
2666  	yaffsfs_Lock();
2667  	dev = yaffsfs_FindDevice(path, &dummy);
2668  	if (dev && dev->is_mounted) {
2669  		retVal = yaffs_get_n_free_chunks(dev);
2670  		retVal *= dev->data_bytes_per_chunk;
2671  
2672  	} else
2673  		yaffsfs_SetError(-EINVAL);
2674  
2675  	yaffsfs_Unlock();
2676  	return retVal;
2677  }
2678  
2679  loff_t yaffs_totalspace(const YCHAR *path)
2680  {
2681  	loff_t retVal = -1;
2682  	struct yaffs_dev *dev = NULL;
2683  	YCHAR *dummy;
2684  
2685  	if (!path) {
2686  		yaffsfs_SetError(-EFAULT);
2687  		return -1;
2688  	}
2689  
2690  	if (yaffsfs_CheckPath(path) < 0) {
2691  		yaffsfs_SetError(-ENAMETOOLONG);
2692  		return -1;
2693  	}
2694  
2695  	yaffsfs_Lock();
2696  	dev = yaffsfs_FindDevice(path, &dummy);
2697  	if (dev && dev->is_mounted) {
2698  		retVal = (dev->param.end_block - dev->param.start_block + 1) -
2699  		    dev->param.n_reserved_blocks;
2700  		retVal *= dev->param.chunks_per_block;
2701  		retVal *= dev->data_bytes_per_chunk;
2702  
2703  	} else
2704  		yaffsfs_SetError(-EINVAL);
2705  
2706  	yaffsfs_Unlock();
2707  	return retVal;
2708  }
2709  
2710  int yaffs_inodecount(const YCHAR *path)
2711  {
2712  	loff_t retVal = -1;
2713  	struct yaffs_dev *dev = NULL;
2714  	YCHAR *dummy;
2715  
2716  	if (!path) {
2717  		yaffsfs_SetError(-EFAULT);
2718  		return -1;
2719  	}
2720  
2721  	if (yaffsfs_CheckPath(path) < 0) {
2722  		yaffsfs_SetError(-ENAMETOOLONG);
2723  		return -1;
2724  	}
2725  
2726  	yaffsfs_Lock();
2727  	dev = yaffsfs_FindDevice(path, &dummy);
2728  	if (dev && dev->is_mounted) {
2729  		int n_obj = dev->n_obj;
2730  		if (n_obj > dev->n_hardlinks)
2731  			retVal = n_obj - dev->n_hardlinks;
2732  	}
2733  
2734  	if (retVal < 0)
2735  		yaffsfs_SetError(-EINVAL);
2736  
2737  	yaffsfs_Unlock();
2738  	return retVal;
2739  }
2740  
2741  void yaffs_add_device(struct yaffs_dev *dev)
2742  {
2743  	struct list_head *cfg;
2744  	/* First check that the device is not in the list. */
2745  
2746  	list_for_each(cfg, &yaffsfs_deviceList) {
2747  		if (dev == list_entry(cfg, struct yaffs_dev, dev_list))
2748  			return;
2749  	}
2750  
2751  	dev->is_mounted = 0;
2752  	dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
2753  
2754  	if (!dev->dev_list.next)
2755  		INIT_LIST_HEAD(&dev->dev_list);
2756  
2757  	list_add(&dev->dev_list, &yaffsfs_deviceList);
2758  }
2759  
2760  void yaffs_remove_device(struct yaffs_dev *dev)
2761  {
2762  	list_del_init(&dev->dev_list);
2763  }
2764  
2765  /* Functions to iterate through devices. NB Use with extreme care! */
2766  
2767  static struct list_head *dev_iterator;
2768  void yaffs_dev_rewind(void)
2769  {
2770  	dev_iterator = yaffsfs_deviceList.next;
2771  }
2772  
2773  struct yaffs_dev *yaffs_next_dev(void)
2774  {
2775  	struct yaffs_dev *retval;
2776  
2777  	if (!dev_iterator)
2778  		return NULL;
2779  	if (dev_iterator == &yaffsfs_deviceList)
2780  		return NULL;
2781  
2782  	retval = list_entry(dev_iterator, struct yaffs_dev, dev_list);
2783  	dev_iterator = dev_iterator->next;
2784  	return retval;
2785  }
2786  
2787  /* Directory search stuff. */
2788  
2789  static struct list_head search_contexts;
2790  
2791  static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContxt *dsc)
2792  {
2793  	if (dsc &&
2794  	    dsc->dirObj &&
2795  	    dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
2796  
2797  		dsc->offset = 0;
2798  
2799  		if (list_empty(&dsc->dirObj->variant.dir_variant.children))
2800  			dsc->nextReturn = NULL;
2801  		else
2802  			dsc->nextReturn =
2803  			    list_entry(dsc->dirObj->variant.dir_variant.
2804  				       children.next, struct yaffs_obj,
2805  				       siblings);
2806  	} else {
2807  		/* Hey someone isn't playing nice! */
2808  	}
2809  }
2810  
2811  static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContxt *dsc)
2812  {
2813  	if (dsc &&
2814  	    dsc->dirObj &&
2815  	    dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
2816  
2817  		if (dsc->nextReturn == NULL ||
2818  		    list_empty(&dsc->dirObj->variant.dir_variant.children))
2819  			dsc->nextReturn = NULL;
2820  		else {
2821  			struct list_head *next = dsc->nextReturn->siblings.next;
2822  
2823  			if (next == &dsc->dirObj->variant.dir_variant.children)
2824  				dsc->nextReturn = NULL;	/* end of list */
2825  			else
2826  				dsc->nextReturn = list_entry(next,
2827  							     struct yaffs_obj,
2828  							     siblings);
2829  		}
2830  	} else {
2831  		/* Hey someone isn't playing nice! */
2832  	}
2833  }
2834  
2835  static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
2836  {
2837  
2838  	struct list_head *i;
2839  	struct yaffsfs_DirSearchContxt *dsc;
2840  
2841  	/* if search contexts not initilised then skip */
2842  	if (!search_contexts.next)
2843  		return;
2844  
2845  	/* Iterate through the directory search contexts.
2846  	 * If any are the one being removed, then advance the dsc to
2847  	 * the next one to prevent a hanging ptr.
2848  	 */
2849  	list_for_each(i, &search_contexts) {
2850  		dsc = list_entry(i, struct yaffsfs_DirSearchContxt, others);
2851  		if (dsc->nextReturn == obj)
2852  			yaffsfs_DirAdvance(dsc);
2853  	}
2854  
2855  }
2856  
2857  yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
2858  {
2859  	yaffs_DIR *dir = NULL;
2860  	struct yaffs_obj *obj = NULL;
2861  	struct yaffsfs_DirSearchContxt *dsc = NULL;
2862  	int notDir = 0;
2863  	int loop = 0;
2864  
2865  	if (!dirname) {
2866  		yaffsfs_SetError(-EFAULT);
2867  		return NULL;
2868  	}
2869  
2870  	if (yaffsfs_CheckPath(dirname) < 0) {
2871  		yaffsfs_SetError(-ENAMETOOLONG);
2872  		return NULL;
2873  	}
2874  
2875  	yaffsfs_Lock();
2876  
2877  	obj = yaffsfs_FindObject(NULL, dirname, 0, 1, NULL, &notDir, &loop);
2878  
2879  	if (!obj && notDir)
2880  		yaffsfs_SetError(-ENOTDIR);
2881  	else if (loop)
2882  		yaffsfs_SetError(-ELOOP);
2883  	else if (!obj)
2884  		yaffsfs_SetError(-ENOENT);
2885  	else if (obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
2886  		yaffsfs_SetError(-ENOTDIR);
2887  	else {
2888  		int i;
2889  
2890  		for (i = 0, dsc = NULL; i < YAFFSFS_N_DSC && !dsc; i++) {
2891  			if (!yaffsfs_dsc[i].inUse)
2892  				dsc = &yaffsfs_dsc[i];
2893  		}
2894  
2895  		dir = (yaffs_DIR *) dsc;
2896  
2897  		if (dsc) {
2898  			memset(dsc, 0, sizeof(struct yaffsfs_DirSearchContxt));
2899  			dsc->inUse = 1;
2900  			dsc->dirObj = obj;
2901  			yaffs_strncpy(dsc->name, dirname, NAME_MAX);
2902  			INIT_LIST_HEAD(&dsc->others);
2903  
2904  			if (!search_contexts.next)
2905  				INIT_LIST_HEAD(&search_contexts);
2906  
2907  			list_add(&dsc->others, &search_contexts);
2908  			yaffsfs_SetDirRewound(dsc);
2909  		}
2910  
2911  	}
2912  
2913  	yaffsfs_Unlock();
2914  
2915  	return dir;
2916  }
2917  
2918  struct yaffs_dirent *yaffs_readdir(yaffs_DIR * dirp)
2919  {
2920  	struct yaffsfs_DirSearchContxt *dsc;
2921  	struct yaffs_dirent *retVal = NULL;
2922  
2923  	dsc = (struct yaffsfs_DirSearchContxt *) dirp;
2924  	yaffsfs_Lock();
2925  
2926  	if (dsc && dsc->inUse) {
2927  		yaffsfs_SetError(0);
2928  		if (dsc->nextReturn) {
2929  			dsc->de.d_ino =
2930  			    yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
2931  			dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2932  			dsc->de.d_off = dsc->offset++;
2933  			yaffs_get_obj_name(dsc->nextReturn,
2934  					   dsc->de.d_name, NAME_MAX);
2935  			if (yaffs_strnlen(dsc->de.d_name, NAME_MAX + 1) == 0) {
2936  				/* this should not happen! */
2937  				yaffs_strcpy(dsc->de.d_name, _Y("zz"));
2938  			}
2939  			dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2940  			retVal = &dsc->de;
2941  			yaffsfs_DirAdvance(dsc);
2942  		} else
2943  			retVal = NULL;
2944  	} else
2945  		yaffsfs_SetError(-EBADF);
2946  
2947  	yaffsfs_Unlock();
2948  
2949  	return retVal;
2950  
2951  }
2952  
2953  void yaffs_rewinddir(yaffs_DIR *dirp)
2954  {
2955  	struct yaffsfs_DirSearchContxt *dsc;
2956  
2957  	dsc = (struct yaffsfs_DirSearchContxt *) dirp;
2958  
2959  	yaffsfs_Lock();
2960  
2961  	yaffsfs_SetDirRewound(dsc);
2962  
2963  	yaffsfs_Unlock();
2964  }
2965  
2966  int yaffs_closedir(yaffs_DIR *dirp)
2967  {
2968  	struct yaffsfs_DirSearchContxt *dsc;
2969  
2970  	dsc = (struct yaffsfs_DirSearchContxt *) dirp;
2971  
2972  	if (!dsc) {
2973  		yaffsfs_SetError(-EFAULT);
2974  		return -1;
2975  	}
2976  
2977  	yaffsfs_Lock();
2978  	dsc->inUse = 0;
2979  	list_del(&dsc->others);	/* unhook from list */
2980  	yaffsfs_Unlock();
2981  	return 0;
2982  }
2983  
2984  /* End of directory stuff */
2985  
2986  int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2987  {
2988  	struct yaffs_obj *parent = NULL;
2989  	struct yaffs_obj *obj;
2990  	YCHAR *name;
2991  	int retVal = -1;
2992  	int mode = 0;		/* ignore for now */
2993  	int notDir = 0;
2994  	int loop = 0;
2995  
2996  	if (!oldpath || !newpath) {
2997  		yaffsfs_SetError(-EFAULT);
2998  		return -1;
2999  	}
3000  
3001  	if (yaffsfs_CheckPath(newpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) {
3002  		yaffsfs_SetError(-ENAMETOOLONG);
3003  		return -1;
3004  	}
3005  
3006  	yaffsfs_Lock();
3007  	parent = yaffsfs_FindDirectory(NULL, newpath, &name, 0, &notDir, &loop);
3008  	if (!parent && notDir)
3009  		yaffsfs_SetError(-ENOTDIR);
3010  	else if (loop)
3011  		yaffsfs_SetError(-ELOOP);
3012  	else if (!parent || yaffs_strnlen(name, 5) < 1)
3013  		yaffsfs_SetError(-ENOENT);
3014  	else if (yaffsfs_TooManyObjects(parent->my_dev))
3015  		yaffsfs_SetError(-ENFILE);
3016  	else if (parent->my_dev->read_only)
3017  		yaffsfs_SetError(-EROFS);
3018  	else {
3019  		obj = yaffs_create_symlink(parent, name, mode, 0, 0, oldpath);
3020  		if (obj)
3021  			retVal = 0;
3022  		else if (yaffsfs_FindObject
3023  			 (NULL, newpath, 0, 0, NULL, NULL, NULL))
3024  			yaffsfs_SetError(-EEXIST);
3025  		else
3026  			yaffsfs_SetError(-ENOSPC);
3027  	}
3028  
3029  	yaffsfs_Unlock();
3030  
3031  	return retVal;
3032  
3033  }
3034  
3035  int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
3036  {
3037  	struct yaffs_obj *obj = NULL;
3038  	struct yaffs_obj *dir = NULL;
3039  	int retVal = -1;
3040  	int notDir = 0;
3041  	int loop = 0;
3042  
3043  	if (!path || !buf) {
3044  		yaffsfs_SetError(-EFAULT);
3045  		return -1;
3046  	}
3047  
3048  	yaffsfs_Lock();
3049  
3050  	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
3051  
3052  	if (!dir && notDir)
3053  		yaffsfs_SetError(-ENOTDIR);
3054  	else if (loop)
3055  		yaffsfs_SetError(-ELOOP);
3056  	else if (!dir || !obj)
3057  		yaffsfs_SetError(-ENOENT);
3058  	else if (obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
3059  		yaffsfs_SetError(-EINVAL);
3060  	else {
3061  		YCHAR *alias = obj->variant.symlink_variant.alias;
3062  		memset(buf, 0, bufsiz);
3063  		yaffs_strncpy(buf, alias, bufsiz - 1);
3064  		retVal = 0;
3065  	}
3066  	yaffsfs_Unlock();
3067  	return retVal;
3068  }
3069  
3070  int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
3071  {
3072  	/* Creates a link called newpath to existing oldpath */
3073  	struct yaffs_obj *obj = NULL;
3074  	struct yaffs_obj *lnk = NULL;
3075  	struct yaffs_obj *obj_dir = NULL;
3076  	struct yaffs_obj *lnk_dir = NULL;
3077  	int retVal = -1;
3078  	int notDirObj = 0;
3079  	int notDirLnk = 0;
3080  	int objLoop = 0;
3081  	int lnkLoop = 0;
3082  	YCHAR *newname;
3083  
3084  	if (!oldpath || !linkpath) {
3085  		yaffsfs_SetError(-EFAULT);
3086  		return -1;
3087  	}
3088  
3089  	if (yaffsfs_CheckPath(linkpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) {
3090  		yaffsfs_SetError(-ENAMETOOLONG);
3091  		return -1;
3092  	}
3093  
3094  	yaffsfs_Lock();
3095  
3096  	obj = yaffsfs_FindObject(NULL, oldpath, 0, 1,
3097  				 &obj_dir, &notDirObj, &objLoop);
3098  	lnk = yaffsfs_FindObject(NULL, linkpath, 0, 0, NULL, NULL, NULL);
3099  	lnk_dir = yaffsfs_FindDirectory(NULL, linkpath, &newname,
3100  					0, &notDirLnk, &lnkLoop);
3101  
3102  	if ((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk))
3103  		yaffsfs_SetError(-ENOTDIR);
3104  	else if (objLoop || lnkLoop)
3105  		yaffsfs_SetError(-ELOOP);
3106  	else if (!obj_dir || !lnk_dir || !obj)
3107  		yaffsfs_SetError(-ENOENT);
3108  	else if (obj->my_dev->read_only)
3109  		yaffsfs_SetError(-EROFS);
3110  	else if (yaffsfs_TooManyObjects(obj->my_dev))
3111  		yaffsfs_SetError(-ENFILE);
3112  	else if (lnk)
3113  		yaffsfs_SetError(-EEXIST);
3114  	else if (lnk_dir->my_dev != obj->my_dev)
3115  		yaffsfs_SetError(-EXDEV);
3116  	else {
3117  		retVal = yaffsfs_CheckNameLength(newname);
3118  
3119  		if (retVal == 0) {
3120  			lnk = yaffs_link_obj(lnk_dir, newname, obj);
3121  			if (lnk)
3122  				retVal = 0;
3123  			else {
3124  				yaffsfs_SetError(-ENOSPC);
3125  				retVal = -1;
3126  			}
3127  		}
3128  	}
3129  	yaffsfs_Unlock();
3130  
3131  	return retVal;
3132  }
3133  
3134  int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
3135  {
3136  	yaffsfs_SetError(-EINVAL);
3137  	return -1;
3138  }
3139  
3140  /*
3141   * D E B U G   F U N C T I O N S
3142   */
3143  
3144  /*
3145   * yaffs_n_handles()
3146   * Returns number of handles attached to the object
3147   */
3148  int yaffs_n_handles(const YCHAR *path)
3149  {
3150  	struct yaffs_obj *obj;
3151  
3152  	if (!path) {
3153  		yaffsfs_SetError(-EFAULT);
3154  		return -1;
3155  	}
3156  
3157  	if (yaffsfs_CheckPath(path) < 0) {
3158  		yaffsfs_SetError(-ENAMETOOLONG);
3159  		return -1;
3160  	}
3161  
3162  	obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL);
3163  
3164  	if (obj)
3165  		return yaffsfs_CountHandles(obj);
3166  	else
3167  		return -1;
3168  }
3169  
3170  int yaffs_get_error(void)
3171  {
3172  	return yaffsfs_GetLastError();
3173  }
3174  
3175  int yaffs_set_error(int error)
3176  {
3177  	yaffsfs_SetError(error);
3178  	return 0;
3179  }
3180  
3181  int yaffs_dump_dev(const YCHAR *path)
3182  {
3183  #if 0
3184  	YCHAR *rest;
3185  
3186  	struct yaffs_obj *obj = yaffsfs_FindRoot(path, &rest);
3187  
3188  	if (obj) {
3189  		struct yaffs_dev *dev = obj->my_dev;
3190  
3191  		printf("\n"
3192  		       "n_page_writes.......... %d\n"
3193  		       "n_page_reads........... %d\n"
3194  		       "n_erasures....... %d\n"
3195  		       "n_gc_copies............ %d\n"
3196  		       "garbageCollections... %d\n"
3197  		       "passiveGarbageColl'ns %d\n"
3198  		       "\n",
3199  		       dev->n_page_writes,
3200  		       dev->n_page_reads,
3201  		       dev->n_erasures,
3202  		       dev->n_gc_copies,
3203  		       dev->garbageCollections, dev->passiveGarbageCollections);
3204  
3205  	}
3206  #endif
3207  	return 0;
3208  }
3209