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