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