yaffs direct: Fix opening of a directory.
[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                         /*
897                          * A directory can't be opened except for read, so we
898                          * ignore other flags
899                          */
900                         if (is_dir) {
901                                 writeRequested = 0;
902                                 readRequested = 1;
903                                 rwflags = O_RDONLY;
904                         }
905
906                         if(is_dir) {
907                                 dsc = yaffsfs_opendir_reldir_no_lock(reldir, path);
908                                 if (!dsc) {
909                                         openDenied = __LINE__;
910                                         yaffsfs_SetError(-ENFILE);
911                                         errorReported = __LINE__;
912                                 }
913                         }
914
915                         /* Open should fail if O_CREAT and O_EXCL are specified
916                          * for a file that exists.
917                          */
918                         if (!errorReported &&
919                             (oflag & O_EXCL) && (oflag & O_CREAT)) {
920                                 openDenied = __LINE__;
921                                 yaffsfs_SetError(-EEXIST);
922                                 errorReported = __LINE__;
923                         }
924
925                         /* Check file permissions */
926                         if (readRequested && !(obj->yst_mode & S_IRUSR))
927                                 openDenied = __LINE__;
928
929                         if (writeRequested && !(obj->yst_mode & S_IWUSR))
930                                 openDenied = __LINE__;
931
932                         if (!errorReported && writeRequested &&
933                             obj->my_dev->read_only) {
934                                 openDenied = __LINE__;
935                                 yaffsfs_SetError(-EROFS);
936                                 errorReported = __LINE__;
937                         }
938
939                         if (openDenied && !errorReported) {
940                                 yaffsfs_SetError(-EACCES);
941                                 errorReported = __LINE__;
942                         }
943
944                         /* Check sharing of an existing object. */
945                         if (!openDenied) {
946                                 struct yaffsfs_FileDes *fdx;
947                                 int i;
948
949                                 sharedReadAllowed = 1;
950                                 sharedWriteAllowed = 1;
951                                 alreadyReading = 0;
952                                 alreadyWriting = 0;
953                                 for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
954                                         fdx = &yaffsfs_fd[i];
955                                         if (fdx->handleCount > 0 &&
956                                             fdx->inodeId >= 0 &&
957                                             yaffsfs_inode[fdx->inodeId].iObj
958                                             == obj) {
959                                                 if (!fdx->shareRead)
960                                                         sharedReadAllowed = 0;
961                                                 if (!fdx->shareWrite)
962                                                         sharedWriteAllowed = 0;
963                                                 if (fdx->reading)
964                                                         alreadyReading = 1;
965                                                 if (fdx->writing)
966                                                         alreadyWriting = 1;
967                                         }
968                                 }
969
970                                 if ((!sharedReadAllowed && readRequested) ||
971                                     (!shareRead && alreadyReading) ||
972                                     (!sharedWriteAllowed && writeRequested) ||
973                                     (!shareWrite && alreadyWriting)) {
974                                         openDenied = __LINE__;
975                                         yaffsfs_SetError(-EBUSY);
976                                         errorReported = __LINE__;
977                                 }
978                         }
979
980                 }
981
982                 /* If we could not open an existing object, then let's see if
983                  * the directory exists. If not, error.
984                  */
985                 if (!obj && !errorReported) {
986                         dir = yaffsfs_FindDirectory(reldir, path, &name, 0,
987                                                     &notDir, &loop);
988                         if (!dir && notDir) {
989                                 yaffsfs_SetError(-ENOTDIR);
990                                 errorReported = __LINE__;
991                         } else if (loop) {
992                                 yaffsfs_SetError(-ELOOP);
993                                 errorReported = __LINE__;
994                         } else if (!dir) {
995                                 yaffsfs_SetError(-ENOENT);
996                                 errorReported = __LINE__;
997                         }
998                 }
999
1000                 if (!obj && dir && !errorReported && (oflag & O_CREAT)) {
1001                         /* Let's see if we can create this file */
1002                         if (dir->my_dev->read_only) {
1003                                 yaffsfs_SetError(-EROFS);
1004                                 errorReported = __LINE__;
1005                         } else if (yaffsfs_TooManyObjects(dir->my_dev)) {
1006                                 yaffsfs_SetError(-ENFILE);
1007                                 errorReported = __LINE__;
1008                         } else
1009                                 obj = yaffs_create_file(dir, name, mode, 0, 0);
1010
1011                         if (!obj && !errorReported) {
1012                                 yaffsfs_SetError(-ENOSPC);
1013                                 errorReported = __LINE__;
1014                         }
1015                 }
1016
1017                 if (!obj && dir && !errorReported && !(oflag & O_CREAT)) {
1018                         yaffsfs_SetError(-ENOENT);
1019                         errorReported = __LINE__;
1020                 }
1021
1022                 if (obj && !openDenied) {
1023                         int inodeId = yaffsfs_GetInodeIdForObject(obj);
1024
1025                         if (inodeId < 0) {
1026                                 /*
1027                                  * Todo: Fix any problem if inodes run out,
1028                                  * That can't happen if the number of inode
1029                                  * items >= number of handles.
1030                                  */
1031                         }
1032
1033                         fd->inodeId = inodeId;
1034                         fd->reading = readRequested;
1035                         fd->writing = writeRequested;
1036                         fd->append = (oflag & O_APPEND) ? 1 : 0;
1037                         fd->shareRead = shareRead;
1038                         fd->shareWrite = shareWrite;
1039                         fd->isDir = is_dir;
1040
1041                         if(is_dir)
1042                                 fd->v.dir = dsc;
1043                         else
1044                                 fd->v.position = 0;
1045
1046                         /* Hook inode to object */
1047                         obj->my_inode = (void *)&yaffsfs_inode[inodeId];
1048
1049                         if (!is_dir && (oflag & O_TRUNC) && fd->writing)
1050                                 yaffs_resize_file(obj, 0);
1051                 } else {
1052                         if (dsc)
1053                                 yaffsfs_closedir_no_lock(dsc);
1054                         dsc = NULL;
1055                         yaffsfs_PutHandle(handle);
1056                         if (!errorReported)
1057                                 yaffsfs_SetError(0);    /* Problem */
1058                         handle = -1;
1059                 }
1060         }
1061
1062         yaffsfs_Unlock();
1063
1064         return handle;
1065 }
1066
1067 int yaffs_open_sharing_reldev(struct yaffs_dev *dev, const YCHAR *path, int oflag,
1068                                 int mode, int sharing)
1069 {
1070         return yaffs_open_sharing_reldir(ROOT_DIR(dev), path,
1071                                         oflag, mode, sharing);
1072 }
1073
1074 int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
1075 {
1076         return yaffs_open_sharing_reldir(NULL, path, oflag, mode, sharing);
1077 }
1078
1079 int yaffs_open_reldir(struct yaffs_obj *reldir,const YCHAR *path, int oflag, int mode)
1080 {
1081         return yaffs_open_sharing_reldir(reldir, path, oflag, mode,
1082                                   YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
1083 }
1084
1085 int yaffs_open_reldev(struct yaffs_dev *dev,const YCHAR *path, int oflag, int mode)
1086 {
1087         return yaffs_open_sharing_reldir(ROOT_DIR(dev), path, oflag, mode,
1088                                   YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
1089 }
1090
1091 int yaffs_open(const YCHAR *path, int oflag, int mode)
1092 {
1093         return yaffs_open_reldir(NULL, path, oflag, mode);
1094 }
1095
1096 static int yaffs_Dofsync(int handle, int datasync)
1097 {
1098         int retVal = -1;
1099         struct yaffs_obj *obj;
1100
1101         yaffsfs_Lock();
1102
1103         obj = yaffsfs_HandleToObject(handle);
1104
1105         if (!obj)
1106                 yaffsfs_SetError(-EBADF);
1107         else if (obj->my_dev->read_only)
1108                 yaffsfs_SetError(-EROFS);
1109         else {
1110                 yaffs_flush_file(obj, 1, datasync, 0);
1111                 retVal = 0;
1112         }
1113
1114         yaffsfs_Unlock();
1115
1116         return retVal;
1117 }
1118
1119 int yaffs_fsync(int handle)
1120 {
1121         return yaffs_Dofsync(handle, 0);
1122 }
1123
1124 int yaffs_flush(int handle)
1125 {
1126         return yaffs_fsync(handle);
1127 }
1128
1129 int yaffs_fdatasync(int handle)
1130 {
1131         return yaffs_Dofsync(handle, 1);
1132 }
1133
1134 int yaffs_close(int handle)
1135 {
1136         struct yaffsfs_Handle *h = NULL;
1137         struct yaffsfs_FileDes *f;
1138         struct yaffs_obj *obj = NULL;
1139         int retVal = -1;
1140
1141         yaffsfs_Lock();
1142
1143         h = yaffsfs_HandleToPointer(handle);
1144         f = yaffsfs_HandleToFileDes(handle);
1145         obj = yaffsfs_HandleToObject(handle);
1146
1147         if (!h || !obj || !f)
1148                 yaffsfs_SetError(-EBADF);
1149         else {
1150                 /* clean up */
1151                 if(!f->isDir)
1152                         yaffs_flush_file(obj, 1, 0, 1);
1153                 yaffsfs_PutHandle(handle);
1154                 retVal = 0;
1155         }
1156
1157         yaffsfs_Unlock();
1158
1159         return retVal;
1160 }
1161
1162 static int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte,
1163                     int isPread, Y_LOFF_T offset)
1164 {
1165         struct yaffsfs_FileDes *fd = NULL;
1166         struct yaffs_obj *obj = NULL;
1167         Y_LOFF_T pos = 0;
1168         Y_LOFF_T startPos = 0;
1169         Y_LOFF_T endPos = 0;
1170         int nRead = 0;
1171         int nToRead = 0;
1172         int totalRead = 0;
1173         Y_LOFF_T maxRead;
1174         u8 *buf = (u8 *) vbuf;
1175
1176         if (yaffsfs_CheckMemRegion(vbuf, nbyte, 1) < 0) {
1177                 yaffsfs_SetError(-EFAULT);
1178                 return -1;
1179         }
1180
1181         yaffsfs_Lock();
1182         fd = yaffsfs_HandleToFileDes(handle);
1183         obj = yaffsfs_HandleToObject(handle);
1184
1185         if (!fd || !obj) {
1186                 /* bad handle */
1187                 yaffsfs_SetError(-EBADF);
1188                 totalRead = -1;
1189         } else if (!fd->reading) {
1190                 /* Not a reading handle */
1191                 yaffsfs_SetError(-EINVAL);
1192                 totalRead = -1;
1193         } else if (nbyte > YAFFS_MAX_RW_SIZE) {
1194                 yaffsfs_SetError(-EINVAL);
1195                 totalRead = -1;
1196         } else {
1197                 if (isPread)
1198                         startPos = offset;
1199                 else
1200                         startPos = fd->v.position;
1201
1202                 pos = startPos;
1203
1204                 if (yaffs_get_obj_length(obj) > pos)
1205                         maxRead = yaffs_get_obj_length(obj) - pos;
1206                 else
1207                         maxRead = 0;
1208
1209                 if (nbyte > maxRead)
1210                         nbyte = maxRead;
1211
1212                 yaffsfs_GetHandle(handle);
1213
1214                 endPos = pos + nbyte;
1215
1216                 if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
1217                     nbyte > YAFFS_MAX_RW_SIZE ||
1218                     endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
1219                         totalRead = -1;
1220                         nbyte = 0;
1221                 }
1222
1223                 while (nbyte > 0) {
1224                         nToRead = YAFFSFS_RW_SIZE -
1225                             (pos & (YAFFSFS_RW_SIZE - 1));
1226                         if (nToRead > (int)nbyte)
1227                                 nToRead = nbyte;
1228
1229                         /* Tricky bit...
1230                          * Need to reverify object in case the device was
1231                          * unmounted in another thread.
1232                          */
1233                         obj = yaffsfs_HandleToObject(handle);
1234                         if (!obj)
1235                                 nRead = 0;
1236                         else
1237                                 nRead = yaffs_file_rd(obj, buf, pos, nToRead);
1238
1239                         if (nRead > 0) {
1240                                 totalRead += nRead;
1241                                 pos += nRead;
1242                                 buf += nRead;
1243                         }
1244
1245                         if (nRead == nToRead)
1246                                 nbyte -= nRead;
1247                         else
1248                                 nbyte = 0;      /* no more to read */
1249
1250                         if (nbyte > 0) {
1251                                 yaffsfs_Unlock();
1252                                 yaffsfs_Lock();
1253                         }
1254
1255                 }
1256
1257                 yaffsfs_PutHandle(handle);
1258
1259                 if (!isPread) {
1260                         if (totalRead >= 0)
1261                                 fd->v.position = startPos + totalRead;
1262                         else
1263                                 yaffsfs_SetError(-EINVAL);
1264                 }
1265
1266         }
1267
1268         yaffsfs_Unlock();
1269
1270         return (totalRead >= 0) ? totalRead : -1;
1271
1272 }
1273
1274 int yaffs_read(int handle, void *buf, unsigned int nbyte)
1275 {
1276         return yaffsfs_do_read(handle, buf, nbyte, 0, 0);
1277 }
1278
1279 int yaffs_pread(int handle, void *buf, unsigned int nbyte, Y_LOFF_T offset)
1280 {
1281         return yaffsfs_do_read(handle, buf, nbyte, 1, offset);
1282 }
1283
1284 static int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte,
1285                      int isPwrite, Y_LOFF_T offset)
1286 {
1287         struct yaffsfs_FileDes *fd = NULL;
1288         struct yaffs_obj *obj = NULL;
1289         Y_LOFF_T pos = 0;
1290         Y_LOFF_T startPos = 0;
1291         Y_LOFF_T endPos;
1292         int nWritten = 0;
1293         int totalWritten = 0;
1294         int write_trhrough = 0;
1295         int nToWrite = 0;
1296         const u8 *buf = (const u8 *)vbuf;
1297
1298         if (yaffsfs_CheckMemRegion(vbuf, nbyte, 0) < 0) {
1299                 yaffsfs_SetError(-EFAULT);
1300                 return -1;
1301         }
1302
1303         yaffsfs_Lock();
1304         fd = yaffsfs_HandleToFileDes(handle);
1305         obj = yaffsfs_HandleToObject(handle);
1306
1307         if (!fd || !obj) {
1308                 /* bad handle */
1309                 yaffsfs_SetError(-EBADF);
1310                 totalWritten = -1;
1311         } else if (!fd->writing) {
1312                 yaffsfs_SetError(-EINVAL);
1313                 totalWritten = -1;
1314         } else if (obj->my_dev->read_only) {
1315                 yaffsfs_SetError(-EROFS);
1316                 totalWritten = -1;
1317         } else {
1318                 if (fd->append)
1319                         startPos = yaffs_get_obj_length(obj);
1320                 else if (isPwrite)
1321                         startPos = offset;
1322                 else
1323                         startPos = fd->v.position;
1324
1325                 yaffsfs_GetHandle(handle);
1326                 pos = startPos;
1327                 endPos = pos + nbyte;
1328
1329                 if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
1330                     nbyte > YAFFS_MAX_RW_SIZE ||
1331                     endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
1332                         totalWritten = -1;
1333                         nbyte = 0;
1334                 }
1335
1336                 while (nbyte > 0) {
1337
1338                         nToWrite = YAFFSFS_RW_SIZE -
1339                             (pos & (YAFFSFS_RW_SIZE - 1));
1340                         if (nToWrite > (int)nbyte)
1341                                 nToWrite = nbyte;
1342
1343                         /* Tricky bit...
1344                          * Need to reverify object in case the device was
1345                          * remounted or unmounted in another thread.
1346                          */
1347                         obj = yaffsfs_HandleToObject(handle);
1348                         if (!obj || obj->my_dev->read_only)
1349                                 nWritten = 0;
1350                         else
1351                                 nWritten =
1352                                     yaffs_wr_file(obj, buf, pos, nToWrite,
1353                                                   write_trhrough);
1354                         if (nWritten > 0) {
1355                                 totalWritten += nWritten;
1356                                 pos += nWritten;
1357                                 buf += nWritten;
1358                         }
1359
1360                         if (nWritten == nToWrite)
1361                                 nbyte -= nToWrite;
1362                         else
1363                                 nbyte = 0;
1364
1365                         if (nWritten < 1 && totalWritten < 1) {
1366                                 yaffsfs_SetError(-ENOSPC);
1367                                 totalWritten = -1;
1368                         }
1369
1370                         if (nbyte > 0) {
1371                                 yaffsfs_Unlock();
1372                                 yaffsfs_Lock();
1373                         }
1374                 }
1375
1376                 yaffsfs_PutHandle(handle);
1377
1378                 if (!isPwrite) {
1379                         if (totalWritten > 0)
1380                                 fd->v.position = startPos + totalWritten;
1381                         else
1382                                 yaffsfs_SetError(-EINVAL);
1383                 }
1384         }
1385
1386         yaffsfs_Unlock();
1387
1388         return (totalWritten >= 0) ? totalWritten : -1;
1389 }
1390
1391 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
1392 {
1393         return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
1394 }
1395
1396 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, Y_LOFF_T offset)
1397 {
1398         return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
1399 }
1400
1401 int yaffs_truncate_reldir(struct yaffs_obj *reldir, const YCHAR *path,
1402                                 Y_LOFF_T new_size)
1403 {
1404         struct yaffs_obj *obj = NULL;
1405         struct yaffs_obj *dir = NULL;
1406         int result = YAFFS_FAIL;
1407         int notDir = 0;
1408         int loop = 0;
1409
1410         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
1411                 yaffsfs_SetError(-EFAULT);
1412                 return -1;
1413         }
1414
1415         if (yaffsfs_CheckPath(path) < 0) {
1416                 yaffsfs_SetError(-ENAMETOOLONG);
1417                 return -1;
1418         }
1419
1420         yaffsfs_Lock();
1421
1422         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
1423         obj = yaffsfs_FollowLink(obj, 0, &loop);
1424
1425         if (!dir && notDir)
1426                 yaffsfs_SetError(-ENOTDIR);
1427         else if (loop)
1428                 yaffsfs_SetError(-ELOOP);
1429         else if (!dir || !obj)
1430                 yaffsfs_SetError(-ENOENT);
1431         else if (obj->my_dev->read_only)
1432                 yaffsfs_SetError(-EROFS);
1433         else if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
1434                 yaffsfs_SetError(-EISDIR);
1435         else if (obj->my_dev->read_only)
1436                 yaffsfs_SetError(-EROFS);
1437         else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1438                 yaffsfs_SetError(-EINVAL);
1439         else
1440                 result = yaffs_resize_file(obj, new_size);
1441
1442         yaffsfs_Unlock();
1443
1444         return (result) ? 0 : -1;
1445 }
1446
1447 int yaffs_truncate_reldev(struct yaffs_dev *dev, const YCHAR *path,
1448                         Y_LOFF_T new_size)
1449 {
1450         return yaffs_truncate_reldir(ROOT_DIR(dev), path, new_size);
1451 }
1452
1453 int yaffs_truncate(const YCHAR *path, Y_LOFF_T new_size)
1454 {
1455         return yaffs_truncate_reldir(NULL, path, new_size);
1456 }
1457
1458 int yaffs_ftruncate(int handle, Y_LOFF_T new_size)
1459 {
1460         struct yaffsfs_FileDes *fd = NULL;
1461         struct yaffs_obj *obj = NULL;
1462         int result = 0;
1463
1464         yaffsfs_Lock();
1465         fd = yaffsfs_HandleToFileDes(handle);
1466         obj = yaffsfs_HandleToObject(handle);
1467
1468         if (!fd || !obj)
1469                 /* bad handle */
1470                 yaffsfs_SetError(-EBADF);
1471         else if (!fd->writing)
1472                 yaffsfs_SetError(-EINVAL);
1473         else if (obj->my_dev->read_only)
1474                 yaffsfs_SetError(-EROFS);
1475         else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1476                 yaffsfs_SetError(-EINVAL);
1477         else
1478                 /* resize the file */
1479                 result = yaffs_resize_file(obj, new_size);
1480         yaffsfs_Unlock();
1481
1482         return (result) ? 0 : -1;
1483
1484 }
1485
1486 Y_LOFF_T yaffs_lseek(int handle, Y_LOFF_T offset, int whence)
1487 {
1488         struct yaffsfs_FileDes *fd = NULL;
1489         struct yaffs_obj *obj = NULL;
1490         Y_LOFF_T pos = -1;
1491         Y_LOFF_T fSize = -1;
1492
1493         yaffsfs_Lock();
1494         fd = yaffsfs_HandleToFileDes(handle);
1495         obj = yaffsfs_HandleToObject(handle);
1496
1497         if (!fd || !obj)
1498                 yaffsfs_SetError(-EBADF);
1499         else if (offset > YAFFS_MAX_FILE_SIZE)
1500                 yaffsfs_SetError(-EINVAL);
1501         else {
1502                 if (whence == SEEK_SET) {
1503                         if (offset >= 0)
1504                                 pos = offset;
1505                 } else if (whence == SEEK_CUR) {
1506                         if ((fd->v.position + offset) >= 0)
1507                                 pos = (fd->v.position + offset);
1508                 } else if (whence == SEEK_END) {
1509                         fSize = yaffs_get_obj_length(obj);
1510                         if (fSize >= 0 && (fSize + offset) >= 0)
1511                                 pos = fSize + offset;
1512                 }
1513
1514                 if (pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE)
1515                         fd->v.position = pos;
1516                 else {
1517                         yaffsfs_SetError(-EINVAL);
1518                         pos = -1;
1519                 }
1520         }
1521
1522         yaffsfs_Unlock();
1523
1524         return pos;
1525 }
1526
1527 static int yaffsfs_DoUnlink_reldir(struct yaffs_obj *reldir,
1528                                 const YCHAR *path, int isDirectory)
1529 {
1530         struct yaffs_obj *dir = NULL;
1531         struct yaffs_obj *obj = NULL;
1532         YCHAR *name;
1533         int result = YAFFS_FAIL;
1534         int notDir = 0;
1535         int loop = 0;
1536
1537         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
1538                 yaffsfs_SetError(-EFAULT);
1539                 return -1;
1540         }
1541
1542         if (yaffsfs_CheckPath(path) < 0) {
1543                 yaffsfs_SetError(-ENAMETOOLONG);
1544                 return -1;
1545         }
1546
1547         yaffsfs_Lock();
1548
1549         obj = yaffsfs_FindObject(reldir, path, 0, 0, NULL, NULL, NULL);
1550         dir = yaffsfs_FindDirectory(reldir, path, &name, 0, &notDir, &loop);
1551
1552         if (!dir && notDir)
1553                 yaffsfs_SetError(-ENOTDIR);
1554         else if (loop)
1555                 yaffsfs_SetError(-ELOOP);
1556         else if (!dir)
1557                 yaffsfs_SetError(-ENOENT);
1558         else if (yaffs_strncmp(name, _Y("."), 2) == 0)
1559                 yaffsfs_SetError(-EINVAL);
1560         else if (!obj)
1561                 yaffsfs_SetError(-ENOENT);
1562         else if (obj->my_dev->read_only)
1563                 yaffsfs_SetError(-EROFS);
1564         else if (!isDirectory &&
1565                  obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1566                 yaffsfs_SetError(-EISDIR);
1567         else if (isDirectory &&
1568                  obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1569                 yaffsfs_SetError(-ENOTDIR);
1570         else if (isDirectory && obj == obj->my_dev->root_dir)
1571                 yaffsfs_SetError(-EBUSY);       /* Can't rmdir a root */
1572         else {
1573                 result = yaffs_unlinker(dir, name);
1574
1575                 if (result == YAFFS_FAIL && isDirectory)
1576                         yaffsfs_SetError(-ENOTEMPTY);
1577         }
1578
1579         yaffsfs_Unlock();
1580
1581         return (result == YAFFS_FAIL) ? -1 : 0;
1582 }
1583
1584 int yaffs_unlink_reldir(struct yaffs_obj *reldir, const YCHAR *path)
1585 {
1586         return yaffsfs_DoUnlink_reldir(reldir, path, 0);
1587 }
1588
1589 int yaffs_unlink_reldev(struct yaffs_dev *dev, const YCHAR *path)
1590 {
1591         return yaffsfs_DoUnlink_reldir(ROOT_DIR(dev), path, 0);
1592 }
1593
1594 int yaffs_unlink(const YCHAR *path)
1595 {
1596         return yaffs_unlink_reldir(NULL, path);
1597 }
1598
1599 int yaffs_funlink(int fd)
1600 {
1601         struct yaffs_obj *obj;
1602         int retVal = -1;
1603
1604         yaffsfs_Lock();
1605         obj = yaffsfs_HandleToObject(fd);
1606
1607         if (!obj)
1608                 yaffsfs_SetError(-EBADF);
1609         else if (obj->my_dev->read_only)
1610                 yaffsfs_SetError(-EROFS);
1611         else if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
1612                         !(list_empty(&obj->variant.dir_variant.children)))
1613                 yaffsfs_SetError(-ENOTEMPTY);
1614         else if (obj == obj->my_dev->root_dir)
1615                 yaffsfs_SetError(-EBUSY);       /* Can't rmdir a root */
1616         else if (yaffs_unlink_obj(obj) == YAFFS_OK)
1617                         retVal = 0;
1618
1619         yaffsfs_Unlock();
1620
1621         return retVal;
1622 }
1623
1624 int yaffs_fgetfl(int fd, int *flags)
1625 {
1626         struct yaffsfs_FileDes *fdp = yaffsfs_HandleToFileDes(fd);
1627         int retVal;
1628
1629         yaffsfs_Lock();
1630
1631         if(!flags || !fdp) {
1632                 yaffsfs_SetError(-EINVAL);
1633                 retVal = -1;
1634         } else {
1635                 if (fdp->reading && fdp->writing)
1636                         *flags = O_RDWR;
1637                 else if (fdp->writing)
1638                         *flags = O_WRONLY;
1639                 else
1640                         *flags = O_RDONLY;
1641                 retVal = 0;
1642         }
1643
1644         yaffsfs_Unlock();
1645         return retVal;
1646 }
1647
1648
1649 static int rename_file_over_dir(struct yaffs_obj *obj, struct yaffs_obj *newobj)
1650 {
1651         if (obj && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY &&
1652             newobj && newobj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1653                 return 1;
1654         else
1655                 return 0;
1656 }
1657
1658 static int rename_dir_over_file(struct yaffs_obj *obj, struct yaffs_obj *newobj)
1659 {
1660         if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
1661             newobj && newobj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1662                 return 1;
1663         else
1664                 return 0;
1665 }
1666
1667 int yaffs_rename_reldir(struct yaffs_obj *reldir,
1668                         const YCHAR *oldPath, const YCHAR *newPath)
1669 {
1670         struct yaffs_obj *olddir = NULL;
1671         struct yaffs_obj *newdir = NULL;
1672         struct yaffs_obj *obj = NULL;
1673         struct yaffs_obj *newobj = NULL;
1674         YCHAR *oldname;
1675         YCHAR *newname;
1676         int result = YAFFS_FAIL;
1677         int rename_allowed = 1;
1678         int notOldDir = 0;
1679         int notNewDir = 0;
1680         int oldLoop = 0;
1681         int newLoop = 0;
1682
1683         YCHAR *alt_newpath = NULL;
1684
1685         if (yaffsfs_CheckMemRegion(oldPath, 0, 0) < 0 ||
1686             yaffsfs_CheckMemRegion(newPath, 0, 0) < 0) {
1687                 yaffsfs_SetError(-EFAULT);
1688                 return -1;
1689         }
1690
1691         if (yaffsfs_CheckPath(oldPath) < 0 || yaffsfs_CheckPath(newPath) < 0) {
1692                 yaffsfs_SetError(-ENAMETOOLONG);
1693                 return -1;
1694         }
1695
1696         if (yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0) {
1697                 yaffsfs_SetError(-ENOMEM);
1698                 return -1;
1699         }
1700         if (alt_newpath)
1701                 newPath = alt_newpath;
1702
1703         yaffsfs_Lock();
1704
1705         olddir = yaffsfs_FindDirectory(reldir, oldPath, &oldname, 0,
1706                                        &notOldDir, &oldLoop);
1707         newdir = yaffsfs_FindDirectory(reldir, newPath, &newname, 0,
1708                                        &notNewDir, &newLoop);
1709         obj = yaffsfs_FindObject(reldir, oldPath, 0, 0, NULL, NULL, NULL);
1710         newobj = yaffsfs_FindObject(reldir, newPath, 0, 0, NULL, NULL, NULL);
1711
1712         /* If the object being renamed is a directory and the
1713          * path ended with a "/" then the olddir == obj.
1714          * We pass through NULL for the old name to tell the lower layers
1715          * to use olddir as the object.
1716          */
1717
1718         if (olddir == obj)
1719                 oldname = NULL;
1720
1721         if ((!olddir && notOldDir) || (!newdir && notNewDir)) {
1722                 yaffsfs_SetError(-ENOTDIR);
1723                 rename_allowed = 0;
1724         } else if (oldLoop || newLoop) {
1725                 yaffsfs_SetError(-ELOOP);
1726                 rename_allowed = 0;
1727         } else if (olddir && oldname &&
1728                         yaffs_strncmp(oldname, _Y("."), 2) == 0) {
1729                 yaffsfs_SetError(-EINVAL);
1730                 rename_allowed = 0;
1731         } else if (!olddir || !newdir || !obj) {
1732                 yaffsfs_SetError(-ENOENT);
1733                 rename_allowed = 0;
1734         } else if (obj->my_dev->read_only) {
1735                 yaffsfs_SetError(-EROFS);
1736                 rename_allowed = 0;
1737         } else if (rename_file_over_dir(obj, newobj)) {
1738                 yaffsfs_SetError(-EISDIR);
1739                 rename_allowed = 0;
1740         } else if (rename_dir_over_file(obj, newobj)) {
1741                 yaffsfs_SetError(-ENOTDIR);
1742                 rename_allowed = 0;
1743         } else if (yaffs_is_non_empty_dir(newobj)) {
1744                 yaffsfs_SetError(-ENOTEMPTY);
1745                 rename_allowed = 0;
1746         } else if (olddir->my_dev != newdir->my_dev) {
1747                 /* Rename must be on same device */
1748                 yaffsfs_SetError(-EXDEV);
1749                 rename_allowed = 0;
1750         } else if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1751                 /*
1752                  * It is a directory, check that it is not being renamed to
1753                  * being its own decendent.
1754                  * Do this by tracing from the new directory back to the root,
1755                  * checking for obj
1756                  */
1757
1758                 struct yaffs_obj *xx = newdir;
1759
1760                 while (rename_allowed && xx) {
1761                         if (xx == obj)
1762                                 rename_allowed = 0;
1763                         xx = xx->parent;
1764                 }
1765                 if (!rename_allowed)
1766                         yaffsfs_SetError(-EINVAL);
1767         }
1768
1769         if (rename_allowed)
1770                 result = yaffs_rename_obj(olddir, oldname, newdir, newname);
1771
1772         yaffsfs_Unlock();
1773
1774         kfree(alt_newpath);
1775
1776         return (result == YAFFS_FAIL) ? -1 : 0;
1777 }
1778
1779 int yaffs_rename_reldev(struct yaffs_dev *dev, const YCHAR *oldPath,
1780                         const YCHAR *newPath)
1781 {
1782         return yaffs_rename_reldir(ROOT_DIR(dev), oldPath, newPath);
1783 }
1784 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1785 {
1786         return yaffs_rename_reldir(NULL, oldPath, newPath);
1787 }
1788
1789 static int yaffsfs_DoStat(struct yaffs_obj *obj, struct yaffs_stat *buf)
1790 {
1791         int retVal = -1;
1792
1793         obj = yaffs_get_equivalent_obj(obj);
1794
1795         if (obj && buf) {
1796                 buf->st_dev = 0;
1797                 buf->st_ino = obj->obj_id;
1798                 buf->st_mode = obj->yst_mode & ~S_IFMT;
1799
1800                 if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1801                         buf->st_mode |= S_IFDIR;
1802                 else if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1803                         buf->st_mode |= S_IFLNK;
1804                 else if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1805                         buf->st_mode |= S_IFREG;
1806
1807                 buf->st_nlink = yaffs_get_obj_link_count(obj);
1808                 buf->st_uid = 0;
1809                 buf->st_gid = 0;
1810                 buf->st_rdev = obj->yst_rdev;
1811                 buf->st_size = yaffs_get_obj_length(obj);
1812                 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
1813                 buf->st_blocks = (buf->st_size + buf->st_blksize - 1) /
1814                     buf->st_blksize;
1815 #if CONFIG_YAFFS_WINCE
1816                 buf->yst_wince_atime[0] = obj->win_atime[0];
1817                 buf->yst_wince_atime[1] = obj->win_atime[1];
1818                 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1819                 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1820                 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1821                 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1822 #else
1823                 buf->yst_atime = obj->yst_atime;
1824                 buf->yst_ctime = obj->yst_ctime;
1825                 buf->yst_mtime = obj->yst_mtime;
1826 #endif
1827                 retVal = 0;
1828         }
1829         return retVal;
1830 }
1831
1832 static int yaffsfs_DoStatOrLStat_reldir(struct yaffs_obj *reldir, const YCHAR *path,
1833                                  struct yaffs_stat *buf, int doLStat)
1834 {
1835         struct yaffs_obj *obj = NULL;
1836         struct yaffs_obj *dir = NULL;
1837         int retVal = -1;
1838         int notDir = 0;
1839         int loop = 0;
1840
1841         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
1842             yaffsfs_CheckMemRegion(buf, sizeof(*buf), 1) < 0) {
1843                 yaffsfs_SetError(-EFAULT);
1844                 return -1;
1845         }
1846
1847         if (yaffsfs_CheckPath(path) < 0) {
1848                 yaffsfs_SetError(-ENAMETOOLONG);
1849                 return -1;
1850         }
1851
1852         yaffsfs_Lock();
1853
1854         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
1855
1856         if (!doLStat && obj)
1857                 obj = yaffsfs_FollowLink(obj, 0, &loop);
1858
1859         if (!dir && notDir)
1860                 yaffsfs_SetError(-ENOTDIR);
1861         else if (loop)
1862                 yaffsfs_SetError(-ELOOP);
1863         else if (!dir || !obj)
1864                 yaffsfs_SetError(-ENOENT);
1865         else
1866                 retVal = yaffsfs_DoStat(obj, buf);
1867
1868         yaffsfs_Unlock();
1869
1870         return retVal;
1871
1872 }
1873
1874 int yaffs_stat_reldir(struct yaffs_obj *reldir, const YCHAR *path,
1875                     struct yaffs_stat *buf)
1876 {
1877         return yaffsfs_DoStatOrLStat_reldir(reldir, path, buf, 0);
1878 }
1879
1880 int yaffs_lstat_reldir(struct yaffs_obj *reldir, const YCHAR *path,
1881                     struct yaffs_stat *buf)
1882 {
1883         return yaffsfs_DoStatOrLStat_reldir(reldir, path, buf, 1);
1884 }
1885
1886 int yaffs_stat_reldev(struct yaffs_dev *dev, const YCHAR *path,
1887                     struct yaffs_stat *buf)
1888 {
1889         return yaffsfs_DoStatOrLStat_reldir(ROOT_DIR(dev), path, buf, 0);
1890 }
1891
1892 int yaffs_lstat_reldev(struct yaffs_dev *dev, const YCHAR *path,
1893                     struct yaffs_stat *buf)
1894 {
1895         return yaffsfs_DoStatOrLStat_reldir(ROOT_DIR(dev), path, buf, 1);
1896 }
1897
1898 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1899 {
1900         return yaffs_stat_reldir(NULL, path, buf);
1901 }
1902
1903 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1904 {
1905         return yaffs_lstat_reldir(NULL, path, buf);
1906 }
1907
1908 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1909 {
1910         struct yaffs_obj *obj;
1911
1912         int retVal = -1;
1913
1914         if (yaffsfs_CheckMemRegion(buf, sizeof(*buf), 1) < 0) {
1915                 yaffsfs_SetError(-EFAULT);
1916                 return -1;
1917         }
1918
1919         yaffsfs_Lock();
1920         obj = yaffsfs_HandleToObject(fd);
1921
1922         if (obj)
1923                 retVal = yaffsfs_DoStat(obj, buf);
1924         else
1925                 /* bad handle */
1926                 yaffsfs_SetError(-EBADF);
1927
1928         yaffsfs_Unlock();
1929
1930         return retVal;
1931 }
1932
1933 static int yaffsfs_DoUtime(struct yaffs_obj *obj,
1934                            const struct yaffs_utimbuf *buf)
1935 {
1936         int retVal = -1;
1937         struct yaffs_utimbuf local;
1938
1939         obj = yaffs_get_equivalent_obj(obj);
1940
1941         if (obj && obj->my_dev->read_only) {
1942                 yaffsfs_SetError(-EROFS);
1943                 return -1;
1944         }
1945
1946 #if !CONFIG_YAFFS_WINCE
1947         if (!buf) {
1948                 local.actime = Y_CURRENT_TIME;
1949                 local.modtime = local.actime;
1950                 buf = &local;
1951         }
1952
1953         if (obj) {
1954                 int result;
1955
1956                 obj->yst_atime = buf->actime;
1957                 obj->yst_mtime = buf->modtime;
1958                 obj->dirty = 1;
1959                 result = yaffs_flush_file(obj, 0, 0, 0);
1960                 retVal = result == YAFFS_OK ? 0 : -1;
1961         }
1962 #endif
1963
1964         return retVal;
1965 }
1966
1967 int yaffs_utime_reldir(struct yaffs_obj *reldir, const YCHAR *path,
1968                      const struct yaffs_utimbuf *buf)
1969 {
1970         struct yaffs_obj *obj = NULL;
1971         struct yaffs_obj *dir = NULL;
1972         int retVal = -1;
1973         int notDir = 0;
1974         int loop = 0;
1975
1976         if (!path) {
1977                 yaffsfs_SetError(-EFAULT);
1978                 return -1;
1979         }
1980
1981         if (yaffsfs_CheckPath(path) < 0) {
1982                 yaffsfs_SetError(-ENAMETOOLONG);
1983                 return -1;
1984         }
1985
1986         yaffsfs_Lock();
1987
1988         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
1989
1990         if (!dir && notDir)
1991                 yaffsfs_SetError(-ENOTDIR);
1992         else if (loop)
1993                 yaffsfs_SetError(-ELOOP);
1994         else if (!dir || !obj)
1995                 yaffsfs_SetError(-ENOENT);
1996         else
1997                 retVal = yaffsfs_DoUtime(obj, buf);
1998
1999         yaffsfs_Unlock();
2000
2001         return retVal;
2002
2003 }
2004
2005 int yaffs_utime_reldev(struct yaffs_dev *dev, const YCHAR *path,
2006                         const struct yaffs_utimbuf *buf)
2007 {
2008         return yaffs_utime_reldir(ROOT_DIR(dev), path, buf);
2009 }
2010
2011 int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf)
2012 {
2013         return yaffs_utime_reldir(NULL, path, buf);
2014 }
2015
2016 int yaffs_futime(int fd, const struct yaffs_utimbuf *buf)
2017 {
2018         struct yaffs_obj *obj;
2019
2020         int retVal = -1;
2021
2022         yaffsfs_Lock();
2023         obj = yaffsfs_HandleToObject(fd);
2024
2025         if (obj)
2026                 retVal = yaffsfs_DoUtime(obj, buf);
2027         else
2028                 /* bad handle */
2029                 yaffsfs_SetError(-EBADF);
2030
2031         yaffsfs_Unlock();
2032
2033         return retVal;
2034 }
2035
2036 #ifndef CONFIG_YAFFS_WINCE
2037 /* xattrib functions */
2038
2039 static int yaffs_do_setxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2040                                   const char *name, const void *data, int size,
2041                                   int flags, int follow)
2042 {
2043         struct yaffs_obj *obj;
2044         struct yaffs_obj *dir;
2045         int notDir = 0;
2046         int loop = 0;
2047
2048         int retVal = -1;
2049
2050         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
2051             yaffsfs_CheckMemRegion(name, 0, 0) < 0 ||
2052             yaffsfs_CheckMemRegion(data, size, 0) < 0) {
2053                 yaffsfs_SetError(-EFAULT);
2054                 return -1;
2055         }
2056
2057         if (yaffsfs_CheckPath(path) < 0) {
2058                 yaffsfs_SetError(-ENAMETOOLONG);
2059                 return -1;
2060         }
2061
2062         yaffsfs_Lock();
2063
2064         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
2065
2066         if (follow)
2067                 obj = yaffsfs_FollowLink(obj, 0, &loop);
2068
2069         if (!dir && notDir)
2070                 yaffsfs_SetError(-ENOTDIR);
2071         else if (loop)
2072                 yaffsfs_SetError(-ELOOP);
2073         else if (!dir || !obj)
2074                 yaffsfs_SetError(-ENOENT);
2075         else {
2076                 retVal = yaffs_set_xattrib(obj, name, data, size, flags);
2077                 if (retVal < 0) {
2078                         yaffsfs_SetError(retVal);
2079                         retVal = -1;
2080                 }
2081         }
2082
2083         yaffsfs_Unlock();
2084
2085         return retVal;
2086
2087 }
2088
2089 int yaffs_setxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2090                         const char *name, const void *data, int size, int flags)
2091 {
2092         return yaffs_do_setxattr_reldir(reldir, path, name, data, size, flags, 1);
2093 }
2094
2095 int yaffs_setxattr_reldev(struct yaffs_dev *dev, const YCHAR *path,
2096                 const char *name, const void *data, int size, int flags)
2097 {
2098         return yaffs_setxattr_reldir(ROOT_DIR(dev), path, name, data, size, flags);
2099 }
2100
2101 int yaffs_setxattr(const YCHAR *path, const char *name,
2102                    const void *data, int size, int flags)
2103 {
2104         return yaffs_setxattr_reldir(NULL, path, name, data, size, flags);
2105 }
2106
2107 int yaffs_lsetxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path, const char *name,
2108                     const void *data, int size, int flags)
2109 {
2110         return yaffs_do_setxattr_reldir(reldir, path, name, data, size, flags, 0);
2111 }
2112
2113 int yaffs_lsetxattr_reldev(struct yaffs_dev *dev, const YCHAR *path, const char *name,
2114                    const void *data, int size, int flags)
2115 {
2116         return yaffs_lsetxattr_reldir(ROOT_DIR(dev), path, name, data, size, flags);
2117 }
2118
2119 int yaffs_lsetxattr(const YCHAR *path, const char *name,
2120                    const void *data, int size, int flags)
2121 {
2122         return yaffs_lsetxattr_reldir(NULL, path, name, data, size, flags);
2123 }
2124
2125 int yaffs_fsetxattr(int fd, const char *name,
2126                     const void *data, int size, int flags)
2127 {
2128         struct yaffs_obj *obj;
2129
2130         int retVal = -1;
2131
2132         if (yaffsfs_CheckMemRegion(name, 0, 0) < 0 ||
2133             yaffsfs_CheckMemRegion(data, size, 0) < 0) {
2134                 yaffsfs_SetError(-EFAULT);
2135                 return -1;
2136         }
2137
2138         yaffsfs_Lock();
2139         obj = yaffsfs_HandleToObject(fd);
2140
2141         if (!obj)
2142                 yaffsfs_SetError(-EBADF);
2143         else {
2144                 retVal = yaffs_set_xattrib(obj, name, data, size, flags);
2145                 if (retVal < 0) {
2146                         yaffsfs_SetError(retVal);
2147                         retVal = -1;
2148                 }
2149         }
2150
2151         yaffsfs_Unlock();
2152
2153         return retVal;
2154 }
2155
2156 static int yaffs_do_getxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2157                         const char *name, void *data, int size, int follow)
2158 {
2159         struct yaffs_obj *obj;
2160         struct yaffs_obj *dir;
2161         int retVal = -1;
2162         int notDir = 0;
2163         int loop = 0;
2164
2165         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
2166             yaffsfs_CheckMemRegion(name, 0, 0) < 0 ||
2167             yaffsfs_CheckMemRegion(data, size, 1) < 0) {
2168                 yaffsfs_SetError(-EFAULT);
2169                 return -1;
2170         }
2171
2172         if (yaffsfs_CheckPath(path) < 0) {
2173                 yaffsfs_SetError(-ENAMETOOLONG);
2174                 return -1;
2175         }
2176
2177         yaffsfs_Lock();
2178
2179         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
2180
2181         if (follow)
2182                 obj = yaffsfs_FollowLink(obj, 0, &loop);
2183
2184         if (!dir && notDir)
2185                 yaffsfs_SetError(-ENOTDIR);
2186         else if (loop)
2187                 yaffsfs_SetError(-ELOOP);
2188         else if (!dir || !obj)
2189                 yaffsfs_SetError(-ENOENT);
2190         else {
2191                 retVal = yaffs_get_xattrib(obj, name, data, size);
2192                 if (retVal < 0) {
2193                         yaffsfs_SetError(retVal);
2194                         retVal = -1;
2195                 }
2196         }
2197         yaffsfs_Unlock();
2198
2199         return retVal;
2200
2201 }
2202
2203 int yaffs_getxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2204                         const char *name, void *data, int size)
2205 {
2206         return yaffs_do_getxattr_reldir(reldir, path, name, data, size, 1);
2207 }
2208
2209 int yaffs_getxattr_reldev(struct yaffs_dev *dev, const YCHAR *path, const char *name, void *data, int size)
2210 {
2211         return yaffs_getxattr_reldir(ROOT_DIR(dev), path, name, data, size);
2212 }
2213
2214 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
2215 {
2216         return yaffs_getxattr_reldir(NULL, path, name, data, size);
2217 }
2218
2219 int yaffs_lgetxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2220                         const char *name, void *data, int size)
2221 {
2222         return yaffs_do_getxattr_reldir(reldir, path, name, data, size, 0);
2223 }
2224
2225 int yaffs_lgetxattr_reldev(struct yaffs_dev *dev, const YCHAR *path, const char *name, void *data, int size)
2226 {
2227         return yaffs_lgetxattr_reldir(ROOT_DIR(dev), path, name, data, size);
2228 }
2229
2230 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
2231 {
2232         return yaffs_lgetxattr_reldir(NULL, path, name, data, size);
2233 }
2234
2235 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
2236 {
2237         struct yaffs_obj *obj;
2238
2239         int retVal = -1;
2240
2241         if (yaffsfs_CheckMemRegion(name, 0, 0) < 0 ||
2242             yaffsfs_CheckMemRegion(data, size, 1) < 0) {
2243                 yaffsfs_SetError(-EFAULT);
2244                 return -1;
2245         }
2246
2247         yaffsfs_Lock();
2248         obj = yaffsfs_HandleToObject(fd);
2249
2250         if (obj) {
2251                 retVal = yaffs_get_xattrib(obj, name, data, size);
2252                 if (retVal < 0) {
2253                         yaffsfs_SetError(retVal);
2254                         retVal = -1;
2255                 }
2256         } else
2257                 /* bad handle */
2258                 yaffsfs_SetError(-EBADF);
2259
2260         yaffsfs_Unlock();
2261
2262         return retVal;
2263 }
2264
2265 static int yaffs_do_listxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2266                                 char *data, int size, int follow)
2267 {
2268         struct yaffs_obj *obj = NULL;
2269         struct yaffs_obj *dir = NULL;
2270         int retVal = -1;
2271         int notDir = 0;
2272         int loop = 0;
2273
2274         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
2275             yaffsfs_CheckMemRegion(data, size, 1) < 0) {
2276                 yaffsfs_SetError(-EFAULT);
2277                 return -1;
2278         }
2279
2280         if (yaffsfs_CheckPath(path) < 0) {
2281                 yaffsfs_SetError(-ENAMETOOLONG);
2282                 return -1;
2283         }
2284
2285         yaffsfs_Lock();
2286
2287         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
2288
2289         if (follow)
2290                 obj = yaffsfs_FollowLink(obj, 0, &loop);
2291
2292         if (!dir && notDir)
2293                 yaffsfs_SetError(-ENOTDIR);
2294         else if (loop)
2295                 yaffsfs_SetError(-ELOOP);
2296         else if (!dir || !obj)
2297                 yaffsfs_SetError(-ENOENT);
2298         else {
2299                 retVal = yaffs_list_xattrib(obj, data, size);
2300                 if (retVal < 0) {
2301                         yaffsfs_SetError(retVal);
2302                         retVal = -1;
2303                 }
2304         }
2305
2306         yaffsfs_Unlock();
2307
2308         return retVal;
2309
2310 }
2311
2312 int yaffs_listxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2313                         char *data, int size)
2314 {
2315         return yaffs_do_listxattr_reldir(reldir, path, data, size, 1);
2316 }
2317
2318 int yaffs_listxattr_reldev(struct yaffs_dev *dev, const YCHAR *path, char *data, int size)
2319 {
2320         return yaffs_listxattr_reldir(ROOT_DIR(dev), path, data, size);
2321 }
2322
2323 int yaffs_listxattr(const YCHAR *path, char *data, int size)
2324 {
2325         return yaffs_listxattr_reldir(NULL, path, data, size);
2326 }
2327
2328 int yaffs_llistxattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2329                         char *data, int size)
2330 {
2331         return yaffs_do_listxattr_reldir(reldir, path, data, size, 0);
2332 }
2333
2334 int yaffs_llistxattr_reldev(struct yaffs_dev *dev, const YCHAR *path, char *data, int size)
2335 {
2336         return yaffs_llistxattr_reldir(ROOT_DIR(dev), path, data, size);
2337 }
2338
2339 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
2340 {
2341         return yaffs_llistxattr_reldir(NULL, path, data, size);
2342 }
2343
2344 int yaffs_flistxattr(int fd, char *data, int size)
2345 {
2346         struct yaffs_obj *obj;
2347
2348         int retVal = -1;
2349
2350         if (yaffsfs_CheckMemRegion(data, size, 1) < 0) {
2351                 yaffsfs_SetError(-EFAULT);
2352                 return -1;
2353         }
2354
2355         yaffsfs_Lock();
2356         obj = yaffsfs_HandleToObject(fd);
2357
2358         if (obj) {
2359                 retVal = yaffs_list_xattrib(obj, data, size);
2360                 if (retVal < 0) {
2361                         yaffsfs_SetError(retVal);
2362                         retVal = -1;
2363                 }
2364         } else
2365                 /* bad handle */
2366                 yaffsfs_SetError(-EBADF);
2367
2368         yaffsfs_Unlock();
2369
2370         return retVal;
2371 }
2372
2373 static int yaffs_do_removexattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2374                                 const char *name, int follow)
2375 {
2376         struct yaffs_obj *obj = NULL;
2377         struct yaffs_obj *dir = NULL;
2378         int notDir = 0;
2379         int loop = 0;
2380         int retVal = -1;
2381
2382         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
2383             yaffsfs_CheckMemRegion(name, 0, 0) < 0) {
2384                 yaffsfs_SetError(-EFAULT);
2385                 return -1;
2386         }
2387
2388         if (yaffsfs_CheckPath(path) < 0) {
2389                 yaffsfs_SetError(-ENAMETOOLONG);
2390                 return -1;
2391         }
2392
2393         yaffsfs_Lock();
2394
2395         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
2396
2397         if (follow)
2398                 obj = yaffsfs_FollowLink(obj, 0, &loop);
2399
2400         if (!dir && notDir)
2401                 yaffsfs_SetError(-ENOTDIR);
2402         else if (loop)
2403                 yaffsfs_SetError(-ELOOP);
2404         else if (!dir || !obj)
2405                 yaffsfs_SetError(-ENOENT);
2406         else {
2407                 retVal = yaffs_remove_xattrib(obj, name);
2408                 if (retVal < 0) {
2409                         yaffsfs_SetError(retVal);
2410                         retVal = -1;
2411                 }
2412         }
2413
2414         yaffsfs_Unlock();
2415
2416         return retVal;
2417
2418 }
2419
2420 int yaffs_removexattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2421                         const char *name)
2422 {
2423         return yaffs_do_removexattr_reldir(reldir, path, name, 1);
2424 }
2425
2426 int yaffs_removexattr_reldev(struct yaffs_dev *dev, const YCHAR *path, const char *name)
2427 {
2428         return yaffs_removexattr_reldir(ROOT_DIR(dev), path, name);
2429 }
2430
2431 int yaffs_removexattr(const YCHAR *path, const char *name)
2432 {
2433         return yaffs_removexattr_reldir(NULL, path, name);
2434 }
2435
2436 int yaffs_lremovexattr_reldir(struct yaffs_obj *reldir, const YCHAR *path,
2437                         const char *name)
2438 {
2439         return yaffs_do_removexattr_reldir(reldir, path, name, 0);
2440 }
2441
2442 int yaffs_lremovexattr_reldev(struct yaffs_dev *dev, const YCHAR *path, const char *name)
2443 {
2444         return yaffs_lremovexattr_reldir(ROOT_DIR(dev), path, name);
2445 }
2446
2447 int yaffs_lremovexattr(const YCHAR *path, const char *name)
2448 {
2449         return yaffs_lremovexattr_reldir(NULL, path, name);
2450 }
2451
2452 int yaffs_fremovexattr(int fd, const char *name)
2453 {
2454         struct yaffs_obj *obj;
2455
2456         int retVal = -1;
2457
2458         if (yaffsfs_CheckMemRegion(name, 0, 0) < 0) {
2459                 yaffsfs_SetError(-EFAULT);
2460                 return -1;
2461         }
2462
2463         yaffsfs_Lock();
2464         obj = yaffsfs_HandleToObject(fd);
2465
2466         if (obj) {
2467                 retVal = yaffs_remove_xattrib(obj, name);
2468                 if (retVal < 0) {
2469                         yaffsfs_SetError(retVal);
2470                         retVal = -1;
2471                 }
2472         } else
2473                 /* bad handle */
2474                 yaffsfs_SetError(-EBADF);
2475
2476         yaffsfs_Unlock();
2477
2478         return retVal;
2479 }
2480 #endif
2481
2482 #ifdef CONFIG_YAFFS_WINCE
2483 int yaffs_get_wince_times(int fd, unsigned *wctime,
2484                           unsigned *watime, unsigned *wmtime)
2485 {
2486         struct yaffs_obj *obj;
2487
2488         int retVal = -1;
2489
2490         yaffsfs_Lock();
2491         obj = yaffsfs_HandleToObject(fd);
2492
2493         if (obj) {
2494
2495                 if (wctime) {
2496                         wctime[0] = obj->win_ctime[0];
2497                         wctime[1] = obj->win_ctime[1];
2498                 }
2499                 if (watime) {
2500                         watime[0] = obj->win_atime[0];
2501                         watime[1] = obj->win_atime[1];
2502                 }
2503                 if (wmtime) {
2504                         wmtime[0] = obj->win_mtime[0];
2505                         wmtime[1] = obj->win_mtime[1];
2506                 }
2507
2508                 retVal = 0;
2509         } else
2510                 /*  bad handle */
2511                 yaffsfs_SetError(-EBADF);
2512
2513         yaffsfs_Unlock();
2514
2515         return retVal;
2516 }
2517
2518 int yaffs_set_wince_times(int fd,
2519                           const unsigned *wctime,
2520                           const unsigned *watime, const unsigned *wmtime)
2521 {
2522         struct yaffs_obj *obj;
2523         int result;
2524         int retVal = -1;
2525
2526         yaffsfs_Lock();
2527         obj = yaffsfs_HandleToObject(fd);
2528
2529         if (obj) {
2530
2531                 if (wctime) {
2532                         obj->win_ctime[0] = wctime[0];
2533                         obj->win_ctime[1] = wctime[1];
2534                 }
2535                 if (watime) {
2536                         obj->win_atime[0] = watime[0];
2537                         obj->win_atime[1] = watime[1];
2538                 }
2539                 if (wmtime) {
2540                         obj->win_mtime[0] = wmtime[0];
2541                         obj->win_mtime[1] = wmtime[1];
2542                 }
2543
2544                 obj->dirty = 1;
2545                 result = yaffs_flush_file(obj, 0, 0, 0);
2546                 retVal = 0;
2547         } else
2548                 /* bad handle */
2549                 yaffsfs_SetError(-EBADF);
2550
2551         yaffsfs_Unlock();
2552
2553         return retVal;
2554 }
2555
2556 #endif
2557
2558 static int yaffsfs_DoChMod(struct yaffs_obj *obj, mode_t mode)
2559 {
2560         int result = -1;
2561
2562         if (obj)
2563                 obj = yaffs_get_equivalent_obj(obj);
2564
2565         if (obj) {
2566                 obj->yst_mode = mode;
2567                 obj->dirty = 1;
2568                 result = yaffs_flush_file(obj, 0, 0, 0);
2569         }
2570
2571         return result == YAFFS_OK ? 0 : -1;
2572 }
2573
2574 int yaffs_access_reldir(struct yaffs_obj *reldir, const YCHAR *path, int amode)
2575 {
2576         struct yaffs_obj *obj = NULL;
2577         struct yaffs_obj *dir = NULL;
2578         int notDir = 0;
2579         int loop = 0;
2580         int retval = -1;
2581
2582         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
2583                 yaffsfs_SetError(-EFAULT);
2584                 return -1;
2585         }
2586
2587         if (yaffsfs_CheckPath(path) < 0) {
2588                 yaffsfs_SetError(-ENAMETOOLONG);
2589                 return -1;
2590         }
2591
2592         if (amode & ~(R_OK | W_OK | X_OK)) {
2593                 yaffsfs_SetError(-EINVAL);
2594                 return -1;
2595         }
2596
2597         yaffsfs_Lock();
2598
2599         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
2600         obj = yaffsfs_FollowLink(obj, 0, &loop);
2601
2602         if (!dir && notDir)
2603                 yaffsfs_SetError(-ENOTDIR);
2604         else if (loop)
2605                 yaffsfs_SetError(-ELOOP);
2606         else if (!dir || !obj)
2607                 yaffsfs_SetError(-ENOENT);
2608         else if ((amode & W_OK) && obj->my_dev->read_only)
2609                 yaffsfs_SetError(-EROFS);
2610         else {
2611                 int access_ok = 1;
2612
2613                 if ((amode & R_OK) && !(obj->yst_mode & S_IRUSR))
2614                         access_ok = 0;
2615                 if ((amode & W_OK) && !(obj->yst_mode & S_IWUSR))
2616                         access_ok = 0;
2617                 if ((amode & X_OK) && !(obj->yst_mode & S_IXUSR))
2618                         access_ok = 0;
2619
2620                 if (!access_ok)
2621                         yaffsfs_SetError(-EACCES);
2622                 else
2623                         retval = 0;
2624         }
2625
2626         yaffsfs_Unlock();
2627
2628         return retval;
2629
2630 }
2631
2632 int yaffs_access_reldev(struct yaffs_dev *dev, const YCHAR *path, int amode)
2633 {
2634         return yaffs_access_reldir(ROOT_DIR(dev), path, amode);
2635 }
2636
2637 int yaffs_access(const YCHAR *path, int amode)
2638 {
2639         return yaffs_access_reldir(NULL, path, amode);
2640 }
2641
2642 int yaffs_chmod_reldir(struct yaffs_obj *reldir, const YCHAR *path, mode_t mode)
2643 {
2644         struct yaffs_obj *obj = NULL;
2645         struct yaffs_obj *dir = NULL;
2646         int retVal = -1;
2647         int notDir = 0;
2648         int loop = 0;
2649
2650         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
2651                 yaffsfs_SetError(-EFAULT);
2652                 return -1;
2653         }
2654
2655         if (yaffsfs_CheckPath(path) < 0) {
2656                 yaffsfs_SetError(-ENAMETOOLONG);
2657                 return -1;
2658         }
2659
2660         if (mode & ~(0777)) {
2661                 yaffsfs_SetError(-EINVAL);
2662                 return -1;
2663         }
2664
2665         yaffsfs_Lock();
2666
2667         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
2668         obj = yaffsfs_FollowLink(obj, 0, &loop);
2669
2670         if (!dir && notDir)
2671                 yaffsfs_SetError(-ENOTDIR);
2672         else if (loop)
2673                 yaffsfs_SetError(-ELOOP);
2674         else if (!dir || !obj)
2675                 yaffsfs_SetError(-ENOENT);
2676         else if (obj->my_dev->read_only)
2677                 yaffsfs_SetError(-EROFS);
2678         else
2679                 retVal = yaffsfs_DoChMod(obj, mode);
2680
2681         yaffsfs_Unlock();
2682
2683         return retVal;
2684
2685 }
2686
2687 int yaffs_chmod_reldev(struct yaffs_dev *dev, const YCHAR *path, mode_t mode)
2688 {
2689         return yaffs_chmod_reldir(ROOT_DIR(dev), path, mode);
2690 }
2691
2692 int yaffs_chmod(const YCHAR *path, mode_t mode)
2693 {
2694         return yaffs_chmod_reldir(NULL, path, mode);
2695 }
2696
2697 int yaffs_fchmod(int fd, mode_t mode)
2698 {
2699         struct yaffs_obj *obj;
2700         int retVal = -1;
2701
2702         if (mode & ~(0777)) {
2703                 yaffsfs_SetError(-EINVAL);
2704                 return -1;
2705         }
2706
2707         yaffsfs_Lock();
2708         obj = yaffsfs_HandleToObject(fd);
2709
2710         if (!obj)
2711                 yaffsfs_SetError(-EBADF);
2712         else if (obj->my_dev->read_only)
2713                 yaffsfs_SetError(-EROFS);
2714         else
2715                 retVal = yaffsfs_DoChMod(obj, mode);
2716
2717         yaffsfs_Unlock();
2718
2719         return retVal;
2720 }
2721
2722 int yaffs_mkdir_reldir(struct yaffs_obj *reldir, const YCHAR *path, mode_t mode)
2723 {
2724         struct yaffs_obj *parent = NULL;
2725         struct yaffs_obj *dir = NULL;
2726         YCHAR *name;
2727         YCHAR *alt_path = NULL;
2728         int retVal = -1;
2729         int notDir = 0;
2730         int loop = 0;
2731
2732         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
2733                 yaffsfs_SetError(-EFAULT);
2734                 return -1;
2735         }
2736
2737         if (yaffsfs_CheckPath(path) < 0) {
2738                 yaffsfs_SetError(-ENAMETOOLONG);
2739                 return -1;
2740         }
2741
2742         if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
2743                 yaffsfs_SetError(-ENOMEM);
2744                 return -1;
2745         }
2746         if (alt_path)
2747                 path = alt_path;
2748
2749         yaffsfs_Lock();
2750         parent = yaffsfs_FindDirectory(reldir, path, &name, 0, &notDir, &loop);
2751         if (!parent && notDir)
2752                 yaffsfs_SetError(-ENOTDIR);
2753         else if (loop)
2754                 yaffsfs_SetError(-ELOOP);
2755         else if (!parent)
2756                 yaffsfs_SetError(-ENOENT);
2757         else if (yaffsfs_TooManyObjects(parent->my_dev))
2758                 yaffsfs_SetError(-ENFILE);
2759         else if (yaffs_strnlen(name, 5) == 0) {
2760                 /* Trying to make the root itself */
2761                 yaffsfs_SetError(-EEXIST);
2762         } else if (parent->my_dev->read_only)
2763                 yaffsfs_SetError(-EROFS);
2764         else {
2765                 dir = yaffs_create_dir(parent, name, mode, 0, 0);
2766                 if (dir)
2767                         retVal = 0;
2768                 else if (yaffs_find_by_name(parent, name))
2769                         yaffsfs_SetError(-EEXIST);      /* name exists */
2770                 else
2771                         yaffsfs_SetError(-ENOSPC);      /* assume no space */
2772         }
2773
2774         yaffsfs_Unlock();
2775
2776         kfree(alt_path);
2777
2778         return retVal;
2779 }
2780
2781 int yaffs_mkdir_reldev(struct yaffs_dev *dev, const YCHAR *path, mode_t mode)
2782 {
2783         return yaffs_mkdir_reldir(ROOT_DIR(dev), path, mode);
2784 }
2785
2786 int yaffs_mkdir(const YCHAR *path, mode_t mode)
2787 {
2788         return yaffs_mkdir_reldir(NULL, path, mode);
2789 }
2790
2791 int yaffs_rmdir_reldir(struct yaffs_obj *reldir, const YCHAR *path)
2792 {
2793         int result;
2794         YCHAR *alt_path;
2795
2796         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
2797                 yaffsfs_SetError(-EFAULT);
2798                 return -1;
2799         }
2800
2801         if (yaffsfs_CheckPath(path) < 0) {
2802                 yaffsfs_SetError(-ENAMETOOLONG);
2803                 return -1;
2804         }
2805
2806         if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
2807                 yaffsfs_SetError(-ENOMEM);
2808                 return -1;
2809         }
2810         if (alt_path)
2811                 path = alt_path;
2812         result = yaffsfs_DoUnlink_reldir(reldir, path, 1);
2813
2814         kfree(alt_path);
2815
2816         return result;
2817 }
2818
2819 int yaffs_rmdir_reldev(struct yaffs_dev *dev, const YCHAR *path)
2820 {
2821         return yaffs_rmdir_reldir(ROOT_DIR(dev), path);
2822 }
2823
2824 int yaffs_rmdir(const YCHAR *path)
2825 {
2826         return yaffs_rmdir_reldir(NULL, path);
2827 }
2828
2829 /*
2830  * The mount/unmount/sync functions act on devices rather than reldirs.
2831  */
2832 void *yaffs_getdev(const YCHAR *path)
2833 {
2834         struct yaffs_dev *dev = NULL;
2835         YCHAR *dummy;
2836         dev = yaffsfs_FindDevice(path, &dummy);
2837         return (void *)dev;
2838 }
2839
2840 int yaffs_mount_common(struct yaffs_dev *dev, const YCHAR *path,
2841                                 int read_only, int skip_checkpt)
2842 {
2843         int retVal = -1;
2844         int result = YAFFS_FAIL;
2845
2846         if (!dev) {
2847                 if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
2848                         yaffsfs_SetError(-EFAULT);
2849                         return -1;
2850                 }
2851
2852                 yaffs_trace(YAFFS_TRACE_MOUNT, "yaffs: Mounting %s", path);
2853
2854                 if (yaffsfs_CheckPath(path) < 0) {
2855                         yaffsfs_SetError(-ENAMETOOLONG);
2856                         return -1;
2857                 }
2858         }
2859
2860         yaffsfs_Lock();
2861
2862         yaffsfs_InitHandles();
2863
2864         if (!dev)
2865                 dev = yaffsfs_FindMountPoint(path);
2866
2867         if (dev) {
2868                 if (!dev->is_mounted) {
2869                         dev->read_only = read_only ? 1 : 0;
2870                         if (skip_checkpt) {
2871                                 u8 skip = dev->param.skip_checkpt_rd;
2872                                 dev->param.skip_checkpt_rd = 1;
2873                                 result = yaffs_guts_initialise(dev);
2874                                 dev->param.skip_checkpt_rd = skip;
2875                         } else {
2876                                 result = yaffs_guts_initialise(dev);
2877                         }
2878
2879                         if (result == YAFFS_FAIL)
2880                                 yaffsfs_SetError(-ENOMEM);
2881                         retVal = result ? 0 : -1;
2882
2883                 } else
2884                         yaffsfs_SetError(-EBUSY);
2885         } else
2886                 yaffsfs_SetError(-ENODEV);
2887
2888         yaffsfs_Unlock();
2889         return retVal;
2890
2891 }
2892
2893 int yaffs_mount3_reldev(struct yaffs_dev *dev, int read_only, int skip_checkpt)
2894 {
2895         return yaffs_mount_common(dev, NULL, read_only, skip_checkpt);
2896 }
2897
2898 int yaffs_mount3(const YCHAR *path, int read_only, int skip_checkpt)
2899 {
2900         return yaffs_mount_common(NULL, path, read_only, skip_checkpt);
2901 }
2902
2903 int yaffs_mount2_reldev(struct yaffs_dev *dev, int readonly)
2904 {
2905         return yaffs_mount_common(dev, NULL, readonly, 0);
2906 }
2907
2908 int yaffs_mount2(const YCHAR *path, int readonly)
2909 {
2910         return yaffs_mount_common(NULL, path, readonly, 0);
2911 }
2912
2913 int yaffs_mount_reldev(struct yaffs_dev *dev)
2914 {
2915         return yaffs_mount_common(dev, NULL, 0, 0);
2916 }
2917
2918 int yaffs_mount(const YCHAR *path)
2919 {
2920         return yaffs_mount_common(NULL, path, 0, 0);
2921 }
2922
2923 static int yaffs_sync_common(struct yaffs_dev *dev,
2924                              const YCHAR *path,
2925                              int do_checkpt)
2926 {
2927         int retVal = -1;
2928         YCHAR *dummy;
2929
2930         if (!dev) {
2931                 if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
2932                         yaffsfs_SetError(-EFAULT);
2933                         return -1;
2934                 }
2935
2936                 if (yaffsfs_CheckPath(path) < 0) {
2937                         yaffsfs_SetError(-ENAMETOOLONG);
2938                         return -1;
2939                 }
2940         }
2941
2942         yaffsfs_Lock();
2943         if (!dev)
2944                 dev = yaffsfs_FindDevice(path, &dummy);
2945
2946         if (dev) {
2947                 if (!dev->is_mounted)
2948                         yaffsfs_SetError(-EINVAL);
2949                 else if (dev->read_only)
2950                         yaffsfs_SetError(-EROFS);
2951                 else {
2952
2953                         yaffs_flush_whole_cache(dev, 0);
2954                         if (do_checkpt)
2955                                 yaffs_checkpoint_save(dev);
2956                         retVal = 0;
2957
2958                 }
2959         } else
2960                 yaffsfs_SetError(-ENODEV);
2961
2962         yaffsfs_Unlock();
2963         return retVal;
2964 }
2965
2966 int yaffs_sync_files_reldev(struct yaffs_dev *dev)
2967 {
2968         return yaffs_sync_common(dev, NULL, 0);
2969 }
2970
2971 int yaffs_sync_files(const YCHAR *path)
2972 {
2973         return yaffs_sync_common(NULL, path, 0);
2974 }
2975
2976 int yaffs_sync_reldev(struct yaffs_dev *dev)
2977 {
2978         return yaffs_sync_common(dev, NULL, 1);
2979 }
2980
2981 int yaffs_sync(const YCHAR *path)
2982 {
2983         return yaffs_sync_common(NULL, path, 1);
2984 }
2985
2986
2987 static int yaffsfs_bg_gc_common(struct yaffs_dev *dev,
2988                                 const YCHAR *path,
2989                                 int urgency)
2990 {
2991         int retVal = -1;
2992         YCHAR *dummy;
2993
2994         if (!dev) {
2995                 if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
2996                         yaffsfs_SetError(-EFAULT);
2997                         return -1;
2998                 }
2999
3000                 if (yaffsfs_CheckPath(path) < 0) {
3001                         yaffsfs_SetError(-ENAMETOOLONG);
3002                         return -1;
3003                 }
3004         }
3005
3006         yaffsfs_Lock();
3007         if (!dev)
3008                 dev = yaffsfs_FindDevice(path, &dummy);
3009
3010         if (dev) {
3011                 if (!dev->is_mounted)
3012                         yaffsfs_SetError(-EINVAL);
3013                 else
3014                         retVal = yaffs_bg_gc(dev, urgency);
3015         } else
3016                 yaffsfs_SetError(-ENODEV);
3017
3018         yaffsfs_Unlock();
3019         return retVal;
3020 }
3021
3022 /* Background gc functions.
3023  * These return 0 when bg done or greater than 0 when gc has been
3024  * done and there is still a lot of garbage to be cleaned up.
3025  */
3026
3027 int yaffs_do_background_gc(const YCHAR *path, int urgency)
3028 {
3029         return yaffsfs_bg_gc_common(NULL, path, urgency);
3030 }
3031
3032 int yaffs_do_background_gc_reldev(struct yaffs_dev *dev, int urgency)
3033 {
3034         return yaffsfs_bg_gc_common(dev, NULL, urgency);
3035 }
3036
3037 static int yaffsfs_IsDevBusy(struct yaffs_dev *dev)
3038 {
3039         int i;
3040         struct yaffs_obj *obj;
3041
3042         for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
3043                 obj = yaffsfs_HandleToObject(i);
3044                 if (obj && obj->my_dev == dev)
3045                         return 1;
3046         }
3047         return 0;
3048 }
3049
3050 int yaffs_remount_common(struct yaffs_dev *dev, const YCHAR *path,
3051                        int force, int read_only)
3052 {
3053         int retVal = -1;
3054
3055         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
3056                 yaffsfs_SetError(-EFAULT);
3057                 return -1;
3058         }
3059
3060         if (yaffsfs_CheckPath(path) < 0) {
3061                 yaffsfs_SetError(-ENAMETOOLONG);
3062                 return -1;
3063         }
3064
3065         yaffsfs_Lock();
3066         if (!dev)
3067                 dev = yaffsfs_FindMountPoint(path);
3068
3069         if (dev) {
3070                 if (dev->is_mounted) {
3071                         yaffs_flush_whole_cache(dev, 0);
3072
3073                         if (force || !yaffsfs_IsDevBusy(dev)) {
3074                                 if (read_only)
3075                                         yaffs_checkpoint_save(dev);
3076                                 dev->read_only = read_only ? 1 : 0;
3077                                 retVal = 0;
3078                         } else
3079                                 yaffsfs_SetError(-EBUSY);
3080
3081                 } else
3082                         yaffsfs_SetError(-EINVAL);
3083
3084         } else
3085                 yaffsfs_SetError(-ENODEV);
3086
3087         yaffsfs_Unlock();
3088         return retVal;
3089
3090 }
3091
3092 int yaffs_remount_reldev(struct yaffs_dev *dev, int force, int read_only)
3093 {
3094         return yaffs_remount_common(dev, NULL, force, read_only);
3095 }
3096 int yaffs_remount(const YCHAR *path, int force, int read_only)
3097 {
3098         return yaffs_remount_common(NULL, path, force, read_only);
3099 }
3100
3101 int yaffs_unmount2_common(struct yaffs_dev *dev, const YCHAR *path, int force)
3102 {
3103         int retVal = -1;
3104
3105         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
3106                 yaffsfs_SetError(-EFAULT);
3107                 return -1;
3108         }
3109
3110         if (yaffsfs_CheckPath(path) < 0) {
3111                 yaffsfs_SetError(-ENAMETOOLONG);
3112                 return -1;
3113         }
3114
3115         yaffsfs_Lock();
3116         if (!dev)
3117                 dev = yaffsfs_FindMountPoint(path);
3118
3119         if (dev) {
3120                 if (dev->is_mounted) {
3121                         int inUse;
3122                         yaffs_flush_whole_cache(dev, 0);
3123                         yaffs_checkpoint_save(dev);
3124                         inUse = yaffsfs_IsDevBusy(dev);
3125                         if (!inUse || force) {
3126                                 if (inUse)
3127                                         yaffsfs_BreakDeviceHandles(dev);
3128                                 yaffs_deinitialise(dev);
3129
3130                                 retVal = 0;
3131                         } else
3132                                 yaffsfs_SetError(-EBUSY);
3133
3134                 } else
3135                         yaffsfs_SetError(-EINVAL);
3136
3137         } else
3138                 yaffsfs_SetError(-ENODEV);
3139
3140         yaffsfs_Unlock();
3141         return retVal;
3142
3143 }
3144
3145 int yaffs_unmount2_reldev(struct yaffs_dev *dev, int force)
3146 {
3147         return yaffs_unmount2_common(dev, NULL, force);
3148 }
3149
3150 int yaffs_unmount2(const YCHAR *path, int force)
3151 {
3152         return yaffs_unmount2_common(NULL, path, force);
3153 }
3154
3155 int yaffs_unmount_reldev(struct yaffs_dev *dev)
3156 {
3157         return yaffs_unmount2_reldev(dev, 0);
3158 }
3159
3160 int yaffs_unmount(const YCHAR *path)
3161 {
3162         return yaffs_unmount2(path, 0);
3163 }
3164
3165 int yaffs_format_common(struct yaffs_dev *dev,
3166                 const YCHAR *path,
3167                 int unmount_flag,
3168                 int force_unmount_flag,
3169                 int remount_flag)
3170 {
3171         int retVal = 0;
3172         int result;
3173
3174         if (!dev) {
3175                 if (!path) {
3176                         yaffsfs_SetError(-EFAULT);
3177                         return -1;
3178                 }
3179
3180                 if (yaffsfs_CheckPath(path) < 0) {
3181                         yaffsfs_SetError(-ENAMETOOLONG);
3182                         return -1;
3183                 }
3184         }
3185
3186         yaffsfs_Lock();
3187         if (!dev)
3188                 dev = yaffsfs_FindMountPoint(path);
3189
3190         if (dev) {
3191                 int was_mounted = dev->is_mounted;
3192
3193                 if (dev->is_mounted && unmount_flag) {
3194                         int inUse;
3195                         yaffs_flush_whole_cache(dev, 0);
3196                         yaffs_checkpoint_save(dev);
3197                         inUse = yaffsfs_IsDevBusy(dev);
3198                         if (!inUse || force_unmount_flag) {
3199                                 if (inUse)
3200                                         yaffsfs_BreakDeviceHandles(dev);
3201                                 yaffs_deinitialise(dev);
3202                         }
3203                 }
3204
3205                 if(dev->is_mounted) {
3206                                 yaffsfs_SetError(-EBUSY);
3207                                 retVal = -1;
3208                 } else {
3209                         yaffs_guts_format_dev(dev);
3210                         if(was_mounted && remount_flag) {
3211                                 result = yaffs_guts_initialise(dev);
3212                                 if (result == YAFFS_FAIL) {
3213                                         yaffsfs_SetError(-ENOMEM);
3214                                         retVal = -1;
3215                                 }
3216                         }
3217                 }
3218         } else {
3219                 yaffsfs_SetError(-ENODEV);
3220                 retVal = -1;
3221         }
3222
3223         yaffsfs_Unlock();
3224         return retVal;
3225
3226 }
3227
3228 int yaffs_format_reldev(struct yaffs_dev *dev,
3229                 int unmount_flag,
3230                 int force_unmount_flag,
3231                 int remount_flag)
3232 {
3233         return yaffs_format_common(dev, NULL, unmount_flag,
3234                         force_unmount_flag, remount_flag);
3235 }
3236
3237 int yaffs_format(const YCHAR *path,
3238                 int unmount_flag,
3239                 int force_unmount_flag,
3240                 int remount_flag)
3241 {
3242         return yaffs_format_common(NULL, path, unmount_flag,
3243                         force_unmount_flag, remount_flag);
3244 }
3245
3246 Y_LOFF_T yaffs_freespace_common(struct yaffs_dev *dev, const YCHAR *path)
3247 {
3248         Y_LOFF_T retVal = -1;
3249         YCHAR *dummy;
3250
3251         if (!dev) {
3252                 if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
3253                         yaffsfs_SetError(-EFAULT);
3254                         return -1;
3255                 }
3256
3257                 if (yaffsfs_CheckPath(path) < 0) {
3258                         yaffsfs_SetError(-ENAMETOOLONG);
3259                         return -1;
3260                 }
3261         }
3262
3263         yaffsfs_Lock();
3264         if (!dev)
3265                 dev = yaffsfs_FindDevice(path, &dummy);
3266         if (dev && dev->is_mounted) {
3267                 retVal = yaffs_get_n_free_chunks(dev);
3268                 retVal *= dev->data_bytes_per_chunk;
3269
3270         } else
3271                 yaffsfs_SetError(-EINVAL);
3272
3273         yaffsfs_Unlock();
3274         return retVal;
3275 }
3276
3277 Y_LOFF_T yaffs_freespace_reldev(struct yaffs_dev *dev)
3278 {
3279         return yaffs_freespace_common(dev, NULL);
3280 }
3281
3282 Y_LOFF_T yaffs_freespace(const YCHAR *path)
3283 {
3284         return yaffs_freespace_common(NULL, path);
3285 }
3286
3287 Y_LOFF_T yaffs_totalspace_common(struct yaffs_dev *dev, const YCHAR *path)
3288 {
3289         Y_LOFF_T retVal = -1;
3290         YCHAR *dummy;
3291
3292         if (!dev) {
3293                 if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
3294                         yaffsfs_SetError(-EFAULT);
3295                         return -1;
3296                 }
3297
3298                 if (yaffsfs_CheckPath(path) < 0) {
3299                         yaffsfs_SetError(-ENAMETOOLONG);
3300                         return -1;
3301                 }
3302         }
3303
3304         yaffsfs_Lock();
3305         if (!dev)
3306                 dev = yaffsfs_FindDevice(path, &dummy);
3307         if (dev && dev->is_mounted) {
3308                 retVal = (dev->param.end_block - dev->param.start_block + 1) -
3309                     dev->param.n_reserved_blocks;
3310                 retVal *= dev->param.chunks_per_block;
3311                 retVal *= dev->data_bytes_per_chunk;
3312
3313         } else
3314                 yaffsfs_SetError(-EINVAL);
3315
3316         yaffsfs_Unlock();
3317         return retVal;
3318 }
3319
3320 Y_LOFF_T yaffs_totalspace_reldev(struct yaffs_dev *dev)
3321 {
3322         return yaffs_totalspace_common(dev, NULL);
3323 }
3324
3325 Y_LOFF_T yaffs_totalspace(const YCHAR *path)
3326 {
3327         return yaffs_totalspace_common(NULL, path);
3328 }
3329
3330 int yaffs_inodecount_common(struct yaffs_dev *dev, const YCHAR *path)
3331 {
3332         Y_LOFF_T retVal = -1;
3333         YCHAR *dummy;
3334
3335         if (!dev) {
3336                 if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
3337                         yaffsfs_SetError(-EFAULT);
3338                         return -1;
3339                 }
3340
3341                 if (yaffsfs_CheckPath(path) < 0) {
3342                         yaffsfs_SetError(-ENAMETOOLONG);
3343                         return -1;
3344                 }
3345         }
3346
3347         yaffsfs_Lock();
3348         if (!dev)
3349                 dev = yaffsfs_FindDevice(path, &dummy);
3350         if (dev && dev->is_mounted) {
3351                 int n_obj = dev->n_obj;
3352                 if (n_obj > dev->n_hardlinks)
3353                         retVal = n_obj - dev->n_hardlinks;
3354         }
3355
3356         if (retVal < 0)
3357                 yaffsfs_SetError(-EINVAL);
3358
3359         yaffsfs_Unlock();
3360         return retVal;
3361 }
3362
3363 int yaffs_inodecount_reldev(struct yaffs_dev *dev)
3364 {
3365         return yaffs_inodecount_common(dev, NULL);
3366 }
3367
3368 int yaffs_inodecount(const YCHAR *path)
3369 {
3370         return yaffs_inodecount_common(NULL, path);
3371 }
3372
3373 void yaffs_add_device(struct yaffs_dev *dev)
3374 {
3375         struct list_head *cfg;
3376         /* First check that the device is not in the list. */
3377
3378         list_for_each(cfg, &yaffsfs_deviceList) {
3379                 if (dev == list_entry(cfg, struct yaffs_dev, dev_list))
3380                         return;
3381         }
3382
3383         dev->is_mounted = 0;
3384         dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
3385
3386         if (!dev->dev_list.next)
3387                 INIT_LIST_HEAD(&dev->dev_list);
3388
3389         list_add(&dev->dev_list, &yaffsfs_deviceList);
3390
3391
3392 }
3393
3394 void yaffs_remove_device(struct yaffs_dev *dev)
3395 {
3396         list_del_init(&dev->dev_list);
3397 }
3398
3399 /* Functions to iterate through devices. NB Use with extreme care! */
3400
3401 static struct list_head *dev_iterator;
3402 void yaffs_dev_rewind(void)
3403 {
3404         dev_iterator = yaffsfs_deviceList.next;
3405 }
3406
3407 struct yaffs_dev *yaffs_next_dev(void)
3408 {
3409         struct yaffs_dev *retval;
3410
3411         if (!dev_iterator)
3412                 return NULL;
3413         if (dev_iterator == &yaffsfs_deviceList)
3414                 return NULL;
3415
3416         retval = list_entry(dev_iterator, struct yaffs_dev, dev_list);
3417         dev_iterator = dev_iterator->next;
3418         return retval;
3419 }
3420
3421 /* Directory search stuff. */
3422
3423 static struct list_head search_contexts;
3424
3425 static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContext *dsc)
3426 {
3427         if (dsc &&
3428             dsc->dirObj &&
3429             dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
3430
3431                 dsc->offset = 0;
3432
3433                 if (list_empty(&dsc->dirObj->variant.dir_variant.children))
3434                         dsc->nextReturn = NULL;
3435                 else
3436                         dsc->nextReturn =
3437                             list_entry(dsc->dirObj->variant.dir_variant.
3438                                        children.next, struct yaffs_obj,
3439                                        siblings);
3440         } else {
3441                 /* Hey someone isn't playing nice! */
3442         }
3443 }
3444
3445 static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContext *dsc)
3446 {
3447         if (dsc &&
3448             dsc->dirObj &&
3449             dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
3450
3451                 if (dsc->nextReturn == NULL ||
3452                     list_empty(&dsc->dirObj->variant.dir_variant.children))
3453                         dsc->nextReturn = NULL;
3454                 else {
3455                         struct list_head *next = dsc->nextReturn->siblings.next;
3456
3457                         if (next == &dsc->dirObj->variant.dir_variant.children)
3458                                 dsc->nextReturn = NULL; /* end of list */
3459                         else
3460                                 dsc->nextReturn = list_entry(next,
3461                                                              struct yaffs_obj,
3462                                                              siblings);
3463                 }
3464         } else {
3465                 /* Hey someone isn't playing nice! */
3466         }
3467 }
3468
3469 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
3470 {
3471
3472         struct list_head *i;
3473         struct yaffsfs_DirSearchContext *dsc;
3474
3475         /* if search contexts not initilised then skip */
3476         if (!search_contexts.next)
3477                 return;
3478
3479         /* Iterate through the directory search contexts.
3480          * If any are the one being removed, then advance the dsc to
3481          * the next one to prevent a hanging ptr.
3482          */
3483         list_for_each(i, &search_contexts) {
3484                 if (i) {
3485                         dsc = list_entry(i, struct yaffsfs_DirSearchContext,
3486                                          others);
3487                         if (dsc->nextReturn == obj)
3488                                 yaffsfs_DirAdvance(dsc);
3489                 }
3490         }
3491
3492 }
3493
3494 static yaffs_DIR *yaffsfs_opendir_reldir_no_lock(struct yaffs_obj *reldir,
3495                                         const YCHAR *dirname)
3496 {
3497         yaffs_DIR *dir = NULL;
3498         struct yaffs_obj *obj = NULL;
3499         struct yaffsfs_DirSearchContext *dsc = NULL;
3500         int notDir = 0;
3501         int loop = 0;
3502
3503         if (yaffsfs_CheckMemRegion(dirname, 0, 0) < 0) {
3504                 yaffsfs_SetError(-EFAULT);
3505                 return NULL;
3506         }
3507
3508         if (yaffsfs_CheckPath(dirname) < 0) {
3509                 yaffsfs_SetError(-ENAMETOOLONG);
3510                 return NULL;
3511         }
3512
3513         obj = yaffsfs_FindObject(reldir, dirname, 0, 1, NULL, &notDir, &loop);
3514         obj = yaffsfs_FollowLink(obj, 0, &loop);
3515
3516         if (!obj && notDir)
3517                 yaffsfs_SetError(-ENOTDIR);
3518         else if (loop)
3519                 yaffsfs_SetError(-ELOOP);
3520         else if (!obj)
3521                 yaffsfs_SetError(-ENOENT);
3522         else if (obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
3523                 yaffsfs_SetError(-ENOTDIR);
3524         else {
3525                 int i;
3526
3527                 for (i = 0, dsc = NULL; i < YAFFSFS_N_DSC && !dsc; i++) {
3528                         if (!yaffsfs_dsc[i].inUse)
3529                                 dsc = &yaffsfs_dsc[i];
3530                 }
3531
3532                 dir = (yaffs_DIR *) dsc;
3533
3534                 if (dsc) {
3535                         memset(dsc, 0, sizeof(struct yaffsfs_DirSearchContext));
3536                         dsc->inUse = 1;
3537                         dsc->dirObj = obj;
3538                         yaffs_strncpy(dsc->name, dirname, NAME_MAX);
3539                         INIT_LIST_HEAD(&dsc->others);
3540
3541                         if (!search_contexts.next)
3542                                 INIT_LIST_HEAD(&search_contexts);
3543
3544                         list_add(&dsc->others, &search_contexts);
3545                         yaffsfs_SetDirRewound(dsc);
3546                 }
3547         }
3548         return dir;
3549 }
3550
3551 yaffs_DIR *yaffs_opendir_reldir(struct yaffs_obj *reldir, const YCHAR *dirname)
3552 {
3553         yaffs_DIR *ret;
3554
3555         yaffsfs_Lock();
3556         ret = yaffsfs_opendir_reldir_no_lock(reldir, dirname);
3557         yaffsfs_Unlock();
3558         return ret;
3559 }
3560
3561 yaffs_DIR *yaffs_opendir_reldev(struct yaffs_dev *dev, const YCHAR *dirname)
3562 {
3563         return yaffs_opendir_reldir(ROOT_DIR(dev), dirname);
3564 }
3565
3566 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
3567 {
3568         return yaffs_opendir_reldir(NULL, dirname);
3569 }
3570
3571 struct yaffs_dirent *yaffsfs_readdir_no_lock(yaffs_DIR * dirp)
3572 {
3573         struct yaffsfs_DirSearchContext *dsc;
3574         struct yaffs_dirent *retVal = NULL;
3575
3576         dsc = (struct yaffsfs_DirSearchContext *) dirp;
3577
3578
3579         if (dsc && dsc->inUse) {
3580                 yaffsfs_SetError(0);
3581                 if (dsc->nextReturn) {
3582                         dsc->de.d_ino =
3583                             yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
3584                         dsc->de.d_dont_use = 0;
3585                         dsc->de.d_off = dsc->offset++;
3586                         yaffs_get_obj_name(dsc->nextReturn,
3587                                            dsc->de.d_name, NAME_MAX);
3588                         if (yaffs_strnlen(dsc->de.d_name, NAME_MAX + 1) == 0) {
3589                                 /* this should not happen! */
3590                                 yaffs_strcpy(dsc->de.d_name, _Y("zz"));
3591                         }
3592                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
3593                         retVal = &dsc->de;
3594                         yaffsfs_DirAdvance(dsc);
3595                 } else
3596                         retVal = NULL;
3597         } else
3598                 yaffsfs_SetError(-EBADF);
3599
3600         return retVal;
3601
3602 }
3603 struct yaffs_dirent *yaffs_readdir(yaffs_DIR * dirp)
3604 {
3605         struct yaffs_dirent *ret;
3606
3607         yaffsfs_Lock();
3608         ret = yaffsfs_readdir_no_lock(dirp);
3609         yaffsfs_Unlock();
3610         return ret;
3611 }
3612
3613 static void yaffsfs_rewinddir_no_lock(yaffs_DIR *dirp)
3614 {
3615         struct yaffsfs_DirSearchContext *dsc;
3616
3617         dsc = (struct yaffsfs_DirSearchContext *) dirp;
3618
3619         if (yaffsfs_CheckMemRegion(dirp, sizeof(*dsc), 0) < 0)
3620                 return;
3621
3622         yaffsfs_SetDirRewound(dsc);
3623
3624 }
3625
3626 void yaffs_rewinddir(yaffs_DIR *dirp)
3627 {
3628         yaffsfs_Lock();
3629         yaffsfs_rewinddir_no_lock(dirp);
3630         yaffsfs_Unlock();
3631 }
3632
3633 struct yaffs_dirent *yaffs_readdir_fd(int fd)
3634 {
3635         struct yaffs_dirent *ret = NULL;
3636         struct yaffsfs_FileDes *f;
3637
3638         yaffsfs_Lock();
3639         f = yaffsfs_HandleToFileDes(fd);
3640         if(f && f->isDir && f->v.dir)
3641                 ret = yaffsfs_readdir_no_lock(f->v.dir);
3642         yaffsfs_Unlock();
3643         return ret;
3644 }
3645
3646 void yaffs_rewinddir_fd(int fd)
3647 {
3648         struct yaffsfs_FileDes *f;
3649
3650         yaffsfs_Lock();
3651         f = yaffsfs_HandleToFileDes(fd);
3652         if(f && f->isDir)
3653                 yaffsfs_rewinddir_no_lock(f->v.dir);
3654         yaffsfs_Unlock();
3655 }
3656
3657
3658 static int yaffsfs_closedir_no_lock(yaffs_DIR *dirp)
3659 {
3660         struct yaffsfs_DirSearchContext *dsc;
3661
3662         dsc = (struct yaffsfs_DirSearchContext *) dirp;
3663
3664         if (yaffsfs_CheckMemRegion(dirp, sizeof(*dsc), 0) < 0) {
3665                 yaffsfs_SetError(-EFAULT);
3666                 return -1;
3667         }
3668
3669         dsc->inUse = 0;
3670         list_del(&dsc->others); /* unhook from list */
3671
3672         return 0;
3673 }
3674
3675 int yaffs_closedir(yaffs_DIR *dirp)
3676 {
3677         int ret;
3678
3679         yaffsfs_Lock();
3680         ret = yaffsfs_closedir_no_lock(dirp);
3681         yaffsfs_Unlock();
3682         return ret;
3683 }
3684
3685 /* End of directory stuff */
3686
3687 int yaffs_symlink_reldir(struct yaffs_obj *reldir,
3688                        const YCHAR *oldpath, const YCHAR *newpath)
3689 {
3690         struct yaffs_obj *parent = NULL;
3691         struct yaffs_obj *obj;
3692         YCHAR *name;
3693         int retVal = -1;
3694         int mode = 0;           /* ignore for now */
3695         int notDir = 0;
3696         int loop = 0;
3697
3698         if (yaffsfs_CheckMemRegion(oldpath, 0, 0) < 0 ||
3699             yaffsfs_CheckMemRegion(newpath, 0, 0) < 0) {
3700                 yaffsfs_SetError(-EFAULT);
3701                 return -1;
3702         }
3703
3704         if (yaffsfs_CheckPath(newpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) {
3705                 yaffsfs_SetError(-ENAMETOOLONG);
3706                 return -1;
3707         }
3708
3709         yaffsfs_Lock();
3710         parent = yaffsfs_FindDirectory(reldir, newpath, &name, 0, &notDir, &loop);
3711         if (!parent && notDir)
3712                 yaffsfs_SetError(-ENOTDIR);
3713         else if (loop)
3714                 yaffsfs_SetError(-ELOOP);
3715         else if (!parent || yaffs_strnlen(name, 5) < 1)
3716                 yaffsfs_SetError(-ENOENT);
3717         else if (yaffsfs_TooManyObjects(parent->my_dev))
3718                 yaffsfs_SetError(-ENFILE);
3719         else if (parent->my_dev->read_only)
3720                 yaffsfs_SetError(-EROFS);
3721         else if (parent) {
3722                 obj = yaffs_create_symlink(parent, name, mode, 0, 0, oldpath);
3723                 if (obj)
3724                         retVal = 0;
3725                 else if (yaffsfs_FindObject(reldir, newpath, 0, 0,
3726                                                 NULL, NULL, NULL))
3727                         yaffsfs_SetError(-EEXIST);
3728                 else
3729                         yaffsfs_SetError(-ENOSPC);
3730         }
3731
3732         yaffsfs_Unlock();
3733
3734         return retVal;
3735
3736 }
3737 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
3738 {
3739         return yaffs_symlink_reldir(NULL, oldpath, newpath);
3740 }
3741
3742 int yaffs_readlink_reldir(struct yaffs_obj *reldir,const YCHAR *path,
3743                         YCHAR *buf, int bufsiz)
3744 {
3745         struct yaffs_obj *obj = NULL;
3746         struct yaffs_obj *dir = NULL;
3747         int retVal = -1;
3748         int notDir = 0;
3749         int loop = 0;
3750
3751         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
3752             yaffsfs_CheckMemRegion(buf, bufsiz, 1) < 0) {
3753                 yaffsfs_SetError(-EFAULT);
3754                 return -1;
3755         }
3756
3757         yaffsfs_Lock();
3758
3759         obj = yaffsfs_FindObject(reldir, path, 0, 1, &dir, &notDir, &loop);
3760
3761         if (!dir && notDir)
3762                 yaffsfs_SetError(-ENOTDIR);
3763         else if (loop)
3764                 yaffsfs_SetError(-ELOOP);
3765         else if (!dir || !obj)
3766                 yaffsfs_SetError(-ENOENT);
3767         else if (obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
3768                 yaffsfs_SetError(-EINVAL);
3769         else {
3770                 YCHAR *alias = obj->variant.symlink_variant.alias;
3771                 memset(buf, 0, bufsiz);
3772                 yaffs_strncpy(buf, alias, bufsiz - 1);
3773                 retVal = 0;
3774         }
3775         yaffsfs_Unlock();
3776         return retVal;
3777 }
3778 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
3779 {
3780         return yaffs_readlink_reldir(NULL, path, buf, bufsiz);
3781 }
3782
3783 int yaffs_link_reldir(struct yaffs_obj *reldir,
3784                         const YCHAR *oldpath, const YCHAR *linkpath)
3785 {
3786         /* Creates a link called newpath to existing oldpath */
3787         struct yaffs_obj *obj = NULL;
3788         struct yaffs_obj *lnk = NULL;
3789         struct yaffs_obj *obj_dir = NULL;
3790         struct yaffs_obj *lnk_dir = NULL;
3791         int retVal = -1;
3792         int notDirObj = 0;
3793         int notDirLnk = 0;
3794         int objLoop = 0;
3795         int lnkLoop = 0;
3796         YCHAR *newname;
3797
3798         if (yaffsfs_CheckMemRegion(oldpath, 0, 0) < 0 ||
3799             yaffsfs_CheckMemRegion(linkpath, 0, 0) < 0) {
3800                 yaffsfs_SetError(-EFAULT);
3801                 return -1;
3802         }
3803
3804         if (yaffsfs_CheckPath(linkpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) {
3805                 yaffsfs_SetError(-ENAMETOOLONG);
3806                 return -1;
3807         }
3808
3809         yaffsfs_Lock();
3810
3811         obj = yaffsfs_FindObject(reldir, oldpath, 0, 1,
3812                                  &obj_dir, &notDirObj, &objLoop);
3813         lnk = yaffsfs_FindObject(reldir, linkpath, 0, 0, NULL, NULL, NULL);
3814         lnk_dir = yaffsfs_FindDirectory(reldir, linkpath, &newname,
3815                                         0, &notDirLnk, &lnkLoop);
3816
3817         if ((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk))
3818                 yaffsfs_SetError(-ENOTDIR);
3819         else if (objLoop || lnkLoop)
3820                 yaffsfs_SetError(-ELOOP);
3821         else if (!obj_dir || !lnk_dir || !obj)
3822                 yaffsfs_SetError(-ENOENT);
3823         else if (obj->my_dev->read_only)
3824                 yaffsfs_SetError(-EROFS);
3825         else if (yaffsfs_TooManyObjects(obj->my_dev))
3826                 yaffsfs_SetError(-ENFILE);
3827         else if (lnk)
3828                 yaffsfs_SetError(-EEXIST);
3829         else if (lnk_dir->my_dev != obj->my_dev)
3830                 yaffsfs_SetError(-EXDEV);
3831         else {
3832                 retVal = yaffsfs_CheckNameLength(newname);
3833
3834                 if (retVal == 0) {
3835                         lnk = yaffs_link_obj(lnk_dir, newname, obj);
3836                         if (lnk)
3837                                 retVal = 0;
3838                         else {
3839                                 yaffsfs_SetError(-ENOSPC);
3840                                 retVal = -1;
3841                         }
3842                 }
3843         }
3844         yaffsfs_Unlock();
3845
3846         return retVal;
3847 }
3848 int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
3849 {
3850         return yaffs_link_reldir(NULL, oldpath, linkpath);
3851 }
3852
3853 int yaffs_mknod_reldir(struct yaffs_obj *reldir, const YCHAR *pathname,
3854                      mode_t mode, dev_t dev_val)
3855 {
3856         (void) pathname;
3857         (void) mode;
3858         (void) dev_val;
3859         (void) reldir;
3860
3861         yaffsfs_SetError(-EINVAL);
3862         return -1;
3863 }
3864
3865 int yaffs_mknod_reldev(struct yaffs_dev *dev, const YCHAR *pathname, mode_t mode, dev_t dev_val)
3866 {
3867         return yaffs_mknod_reldir(ROOT_DIR(dev), pathname, mode, dev_val);
3868 }
3869
3870 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev_val)
3871 {
3872         return yaffs_mknod_reldir(NULL, pathname, mode, dev_val);
3873 }
3874
3875 /*
3876  * D E B U G   F U N C T I O N S
3877  */
3878
3879 /*
3880  * yaffs_n_handles()
3881  * Returns number of handles attached to the object
3882  */
3883 int yaffs_n_handles_reldir(struct yaffs_obj *reldir, const YCHAR *path)
3884 {
3885         struct yaffs_obj *obj;
3886
3887         if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
3888                 yaffsfs_SetError(-EFAULT);
3889                 return -1;
3890         }
3891
3892         if (yaffsfs_CheckPath(path) < 0) {
3893                 yaffsfs_SetError(-ENAMETOOLONG);
3894                 return -1;
3895         }
3896
3897         obj = yaffsfs_FindObject(reldir, path, 0, 1, NULL, NULL, NULL);
3898
3899         if (obj)
3900                 return yaffsfs_CountHandles(obj);
3901         else
3902                 return -1;
3903 }
3904
3905 int yaffs_n_handles(const YCHAR *path)
3906 {
3907         return yaffs_n_handles_reldir(NULL, path);
3908 }
3909
3910 int yaffs_get_error(void)
3911 {
3912         return yaffsfs_GetLastError();
3913 }
3914
3915 int yaffs_set_error(int error)
3916 {
3917         yaffsfs_SetError(error);
3918         return 0;
3919 }
3920
3921 struct yaffs_obj * yaffs_get_obj_from_fd(int handle)
3922 {
3923         return yaffsfs_HandleToObject(handle);
3924 }
3925
3926 int yaffs_dump_dev_reldir(struct yaffs_obj *reldir, const YCHAR *path)
3927 {
3928 #if 1
3929         (void) path;
3930         (void) reldir;
3931 #else
3932         YCHAR *rest;
3933
3934
3935         if (!reldir)
3936                 reldir = yaffsfs_FindRoot(path, &rest);
3937
3938         if (reldir) {
3939                 struct yaffs_dev *dev = reldir->my_dev;
3940
3941                 printf("\n"
3942                        "n_page_writes.......... %d\n"
3943                        "n_page_reads........... %d\n"
3944                        "n_erasures....... %d\n"
3945                        "n_gc_copies............ %d\n"
3946                        "garbageCollections... %d\n"
3947                        "passiveGarbageColl'ns %d\n"
3948                        "\n",
3949                        dev->n_page_writes,
3950                        dev->n_page_reads,
3951                        dev->n_erasures,
3952                        dev->n_gc_copies,
3953                        dev->garbageCollections, dev->passiveGarbageCollections);
3954
3955         }
3956 #endif
3957         return 0;
3958 }
3959
3960 int yaffs_dump_dev(const YCHAR *path)
3961 {
3962         return yaffs_dump_dev_reldir(NULL, path);
3963 }