xref: /openbmc/u-boot/fs/yaffs2/yaffsfs.c (revision 894c3ad2)
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