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