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