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