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