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