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