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