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