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