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