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