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