yaffs More tests
[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 nRead = 0;
885         int nToRead = 0;
886         int totalRead = 0;
887         unsigned int maxRead;
888         u8 *buf = (u8 *)vbuf;
889
890         yaffsfs_Lock();
891         h = yaffsfs_GetHandlePointer(fd);
892         obj = yaffsfs_GetHandleObject(fd);
893
894         if(!h || !obj){
895                 /* bad handle */
896                 yaffsfs_SetError(-EBADF);
897                 totalRead = -1;
898         } else if(!h->reading){
899                 /* Not a reading handle */
900                 yaffsfs_SetError(-EINVAL);
901                 totalRead = -1;
902         } else if(nbyte > YAFFS_MAX_FILE_SIZE){
903                 yaffsfs_SetError(-EINVAL);
904                 totalRead = -1;
905         } else {
906                 if(isPread)
907                         startPos = offset;
908                 else
909                         startPos = h->position;
910
911                 pos = startPos;
912                                         
913                 if(yaffs_get_obj_length(obj) > pos)
914                         maxRead = yaffs_get_obj_length(obj) - pos;
915                 else
916                         maxRead = 0;
917
918                 if(nbyte > maxRead)
919                         nbyte = maxRead;
920
921
922                 yaffsfs_GetHandle(fd);
923
924                 while(nbyte > 0) {
925                         nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
926                         if(nToRead > nbyte)
927                                 nToRead = nbyte;
928
929                         /* Tricky bit... 
930                          * Need to reverify object in case the device was
931                          * unmounted in another thread.
932                          */
933                         obj = yaffsfs_GetHandleObject(fd);
934                         if(!obj)
935                                 nRead = 0;
936                         else
937                                 nRead = yaffs_file_rd(obj,buf,pos,nToRead);
938
939                         if(nRead > 0){
940                                 totalRead += nRead;
941                                 pos += nRead;
942                                 buf += nRead;
943                         }
944
945                         if(nRead == nToRead)
946                                 nbyte-=nRead;
947                         else
948                                 nbyte = 0; /* no more to read */
949                                         
950                                         
951                         if(nbyte > 0){
952                                 yaffsfs_Unlock();
953                                 yaffsfs_Lock();
954                         }
955
956                 }
957
958                 yaffsfs_PutHandle(fd);
959
960                 if(!isPread) {
961                         if(totalRead >= 0)
962                                 h->position = startPos + totalRead;
963                         else {
964                                         /* todo error */
965                         }
966                 }
967
968         }
969
970         yaffsfs_Unlock();
971
972         return (totalRead >= 0) ? totalRead : -1;
973
974 }
975
976 int yaffs_read(int fd, void *buf, unsigned int nbyte)
977 {
978         return yaffsfs_do_read(fd, buf, nbyte, 0, 0);
979 }
980
981 int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
982 {
983         return yaffsfs_do_read(fd, buf, nbyte, 1, offset);
984 }
985
986 int yaffsfs_do_write(int fd, const void *vbuf, unsigned int nbyte, int isPwrite, int offset)
987 {
988         yaffsfs_Handle *h = NULL;
989         struct yaffs_obj *obj = NULL;
990         int pos = 0;
991         int startPos = 0;
992         int nWritten = 0;
993         int totalWritten = 0;
994         int write_trhrough = 0;
995         int nToWrite = 0;
996         const u8 *buf = (const u8 *)vbuf;
997
998         yaffsfs_Lock();
999         h = yaffsfs_GetHandlePointer(fd);
1000         obj = yaffsfs_GetHandleObject(fd);
1001
1002         if(!h || !obj){
1003                 /* bad handle */
1004                 yaffsfs_SetError(-EBADF);
1005                 totalWritten = -1;
1006         } else if( h && obj && (!h->writing || obj->my_dev->read_only)){
1007                 yaffsfs_SetError(-EINVAL);
1008                 totalWritten=-1;
1009         } else {
1010                 if(h->append)
1011                         startPos = yaffs_get_obj_length(obj);
1012                 else if(isPwrite)
1013                         startPos = offset;
1014                 else
1015                         startPos = h->position;
1016
1017                 yaffsfs_GetHandle(fd);
1018                 pos = startPos;
1019                 while(nbyte > 0) {
1020
1021                         nToWrite = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
1022                         if(nToWrite > nbyte)
1023                                 nToWrite = nbyte;
1024
1025                         /* Tricky bit... 
1026                          * Need to reverify object in case the device was
1027                          * remounted or unmounted in another thread.
1028                          */
1029                         obj = yaffsfs_GetHandleObject(fd);
1030                         if(!obj || obj->my_dev->read_only)
1031                                 nWritten = 0;
1032                         else
1033                                 nWritten = yaffs_wr_file(obj,buf,pos,nToWrite,
1034                                                         write_trhrough);
1035                         if(nWritten > 0){
1036                                 totalWritten += nWritten;
1037                                 pos += nWritten;
1038                                 buf += nWritten;
1039                         }
1040
1041                         if(nWritten == nToWrite)
1042                                 nbyte -= nToWrite;
1043                         else
1044                                 nbyte = 0;
1045
1046                         if(nWritten < 1 && totalWritten < 1){
1047                                 yaffsfs_SetError(-ENOSPC);
1048                                 totalWritten = -1;
1049                         }
1050
1051                         if(nbyte > 0){
1052                                 yaffsfs_Unlock();
1053                                 yaffsfs_Lock();
1054                         }
1055                 }
1056
1057                 yaffsfs_PutHandle(fd);
1058
1059                 if(!isPwrite){
1060                         if(totalWritten > 0)
1061                                 h->position = startPos + totalWritten;
1062                         else {
1063                                 /* todo error */
1064                         }
1065                 }
1066         }
1067
1068         yaffsfs_Unlock();
1069
1070         return (totalWritten >= 0) ? totalWritten : -1;
1071 }
1072
1073 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
1074 {
1075         return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
1076 }
1077
1078 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
1079 {
1080         return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
1081 }
1082
1083
1084 int yaffs_truncate(const YCHAR *path,off_t new_size)
1085 {
1086         struct yaffs_obj *obj = NULL;
1087         struct yaffs_obj *dir = NULL;
1088         int result = YAFFS_FAIL;
1089
1090         if(yaffsfs_CheckPath(path) < 0){
1091                 yaffsfs_SetError(-ENAMETOOLONG);
1092                 return -1;
1093         }
1094
1095         yaffsfs_Lock();
1096
1097         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1098
1099         if(!dir)
1100                 yaffsfs_SetError(-ENOTDIR);
1101         else if(!obj)
1102                 yaffsfs_SetError(-ENOENT);
1103         else if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
1104                 yaffsfs_SetError(-EISDIR);
1105         else if(obj->my_dev->read_only)
1106                 yaffsfs_SetError(-EACCES);
1107         else if(new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1108                 yaffsfs_SetError(-EINVAL);
1109         else
1110                 result = yaffs_resize_file(obj,new_size);
1111
1112         yaffsfs_Unlock();
1113
1114         return (result) ? 0 : -1;
1115 }
1116
1117 int yaffs_ftruncate(int fd, off_t new_size)
1118 {
1119         yaffsfs_Handle *h = NULL;
1120         struct yaffs_obj *obj = NULL;
1121         int result = 0;
1122
1123         yaffsfs_Lock();
1124         h = yaffsfs_GetHandlePointer(fd);
1125         obj = yaffsfs_GetHandleObject(fd);
1126
1127         if(!h || !obj)
1128                 /* bad handle */
1129                 yaffsfs_SetError(-EBADF);
1130         else if(obj->my_dev->read_only)
1131                 yaffsfs_SetError(-EACCES);
1132         else if( new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1133                 yaffsfs_SetError(-EINVAL);
1134         else
1135                 /* resize the file */
1136                 result = yaffs_resize_file(obj,new_size);
1137         yaffsfs_Unlock();
1138
1139         return (result) ? 0 : -1;
1140
1141 }
1142
1143 off_t yaffs_lseek(int fd, off_t offset, int whence)
1144 {
1145         yaffsfs_Handle *h = NULL;
1146         struct yaffs_obj *obj = NULL;
1147         int pos = -1;
1148         int fSize = -1;
1149
1150         yaffsfs_Lock();
1151         h = yaffsfs_GetHandlePointer(fd);
1152         obj = yaffsfs_GetHandleObject(fd);
1153
1154         if(!h || !obj)
1155                 yaffsfs_SetError(-EBADF);
1156         else if(offset > YAFFS_MAX_FILE_SIZE)
1157                 yaffsfs_SetError(-EINVAL);
1158         else {
1159                 if(whence == SEEK_SET){
1160                         if(offset >= 0)
1161                                 pos = offset;
1162                 } else if(whence == SEEK_CUR) {
1163                         if( (h->position + offset) >= 0)
1164                                 pos = (h->position + offset);
1165                 } else if(whence == SEEK_END) {
1166                         fSize = yaffs_get_obj_length(obj);
1167                         if(fSize >= 0 && (fSize + offset) >= 0)
1168                                 pos = fSize + offset;
1169                 } 
1170
1171                 if(pos >= 0)
1172                         h->position = pos;
1173                 else
1174                         yaffsfs_SetError(-EINVAL);
1175         }
1176
1177         yaffsfs_Unlock();
1178
1179         return pos;
1180 }
1181
1182
1183 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
1184 {
1185         struct yaffs_obj *dir = NULL;
1186         struct yaffs_obj *obj = NULL;
1187         YCHAR *name;
1188         int result = YAFFS_FAIL;
1189
1190         if(yaffsfs_CheckPath(path) < 0){
1191                 yaffsfs_SetError(-ENAMETOOLONG);
1192                 return -1;
1193         }
1194
1195         yaffsfs_Lock();
1196
1197         obj = yaffsfs_FindObject(NULL,path,0,0,NULL);
1198         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
1199
1200         if(!dir)
1201                 yaffsfs_SetError(-ENOTDIR);
1202         else if(!obj)
1203                 yaffsfs_SetError(-ENOENT);
1204         else if(obj->my_dev->read_only)
1205                 yaffsfs_SetError(-EINVAL);
1206         else if(!isDirectory && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1207                 yaffsfs_SetError(-EISDIR);
1208         else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1209                 yaffsfs_SetError(-ENOTDIR);
1210         else {
1211                 result = yaffs_unlinker(dir,name);
1212
1213                 if(result == YAFFS_FAIL && isDirectory)
1214                         yaffsfs_SetError(-ENOTEMPTY);
1215         }
1216
1217         yaffsfs_Unlock();
1218
1219         /* todo error */
1220
1221         return (result == YAFFS_FAIL) ? -1 : 0;
1222 }
1223
1224
1225 int yaffs_unlink(const YCHAR *path)
1226 {
1227         return yaffsfs_DoUnlink(path,0);
1228 }
1229
1230 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1231 {
1232         struct yaffs_obj *olddir = NULL;
1233         struct yaffs_obj *newdir = NULL;
1234         struct yaffs_obj *obj = NULL;
1235         YCHAR *oldname;
1236         YCHAR *newname;
1237         int result= YAFFS_FAIL;
1238         int rename_allowed = 1;
1239
1240         yaffsfs_Lock();
1241
1242         if(yaffsfs_CheckPath(newPath) < 0){
1243                 yaffsfs_SetError(-ENAMETOOLONG);
1244                 return -1;
1245         }
1246
1247         olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1248         newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1249         obj = yaffsfs_FindObject(NULL,oldPath,0,0,NULL);
1250
1251         if(!olddir || !newdir) {
1252                 yaffsfs_SetError(-ENOTDIR);
1253                 rename_allowed = 0;
1254         } else if(!obj) {
1255                 yaffsfs_SetError(-ENOENT);
1256                 rename_allowed = 0;
1257         } else if(obj->my_dev->read_only){
1258                 yaffsfs_SetError(-EROFS);
1259                 rename_allowed = 0;
1260         } else if(olddir->my_dev != newdir->my_dev) {
1261                 /* Rename must be on same device */
1262                 yaffsfs_SetError(-EXDEV);
1263                 rename_allowed = 0;
1264         } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1265                 /*
1266                  * It is a directory, check that it is not being renamed to
1267                  * being its own decendent.
1268                  * Do this by tracing from the new directory back to the root, checking for obj
1269                  */
1270
1271                 struct yaffs_obj *xx = newdir;
1272
1273                 while( rename_allowed && xx){
1274                         if(xx == obj)
1275                                 rename_allowed = 0;
1276                         xx = xx->parent;
1277                 }
1278                 if(!rename_allowed)
1279                         yaffsfs_SetError(-EINVAL);
1280         }
1281
1282         if(rename_allowed)
1283                 result = yaffs_rename_obj(olddir,oldname,newdir,newname);
1284
1285         yaffsfs_Unlock();
1286
1287         return (result == YAFFS_FAIL) ? -1 : 0;
1288 }
1289
1290
1291 static int yaffsfs_DoStat(struct yaffs_obj *obj,struct yaffs_stat *buf)
1292 {
1293         int retVal = -1;
1294
1295         obj = yaffs_get_equivalent_obj(obj);
1296
1297         if(obj && buf){
1298                 buf->st_dev = (int)obj->my_dev->os_context;
1299                 buf->st_ino = obj->obj_id;
1300                 buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
1301
1302                 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1303                         buf->st_mode |= S_IFDIR;
1304                 else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1305                         buf->st_mode |= S_IFLNK;
1306                 else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1307                         buf->st_mode |= S_IFREG;
1308
1309                 buf->st_nlink = yaffs_get_obj_link_count(obj);
1310                 buf->st_uid = 0;
1311                 buf->st_gid = 0;;
1312                 buf->st_rdev = obj->yst_rdev;
1313                 buf->st_size = yaffs_get_obj_length(obj);
1314                 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
1315                 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1316 #if CONFIG_YAFFS_WINCE
1317                 buf->yst_wince_atime[0] = obj->win_atime[0];
1318                 buf->yst_wince_atime[1] = obj->win_atime[1];
1319                 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1320                 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1321                 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1322                 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1323 #else
1324                 buf->yst_atime = obj->yst_atime;
1325                 buf->yst_ctime = obj->yst_ctime;
1326                 buf->yst_mtime = obj->yst_mtime;
1327 #endif
1328                 retVal = 0;
1329         }
1330         return retVal;
1331 }
1332
1333 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1334 {
1335         struct yaffs_obj *obj=NULL;
1336         struct yaffs_obj *dir=NULL;
1337
1338         int retVal = -1;
1339
1340         if(yaffsfs_CheckPath(path) < 0){
1341                 yaffsfs_SetError(-ENAMETOOLONG);
1342                 return -1;
1343         }
1344
1345         yaffsfs_Lock();
1346
1347         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1348
1349         if(!doLStat && obj)
1350                 obj = yaffsfs_FollowLink(obj,0);
1351
1352         if(!dir)
1353                 yaffsfs_SetError(-ENOTDIR);
1354         else if(!obj)
1355                 yaffsfs_SetError(-ENOENT);
1356         else
1357                 retVal = yaffsfs_DoStat(obj,buf);
1358
1359         yaffsfs_Unlock();
1360
1361         return retVal;
1362
1363 }
1364
1365 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1366 {
1367         return yaffsfs_DoStatOrLStat(path,buf,0);
1368 }
1369
1370 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1371 {
1372         return yaffsfs_DoStatOrLStat(path,buf,1);
1373 }
1374
1375 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1376 {
1377         struct yaffs_obj *obj;
1378
1379         int retVal = -1;
1380
1381         yaffsfs_Lock();
1382         obj = yaffsfs_GetHandleObject(fd);
1383
1384         if(obj)
1385                 retVal = yaffsfs_DoStat(obj,buf);
1386         else
1387                 /* bad handle */
1388                 yaffsfs_SetError(-EBADF);
1389
1390         yaffsfs_Unlock();
1391
1392         return retVal;
1393 }
1394
1395 #ifndef CONFIG_YAFFS_WINCE
1396 /* xattrib functions */
1397
1398
1399 static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags, int follow)
1400 {
1401         struct yaffs_obj *obj;
1402         struct yaffs_obj *dir;
1403
1404         int retVal = -1;
1405
1406         if(yaffsfs_CheckPath(path) < 0){
1407                 yaffsfs_SetError(-ENAMETOOLONG);
1408                 return -1;
1409         }
1410
1411         yaffsfs_Lock();
1412
1413         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1414
1415         if(follow)
1416                 obj = yaffsfs_FollowLink(obj,0);
1417
1418         if(!dir) 
1419                 yaffsfs_SetError(-ENOTDIR);
1420         else if(!obj) 
1421                 yaffsfs_SetError(-ENOENT);
1422         else {
1423                 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1424                 if(retVal< 0){
1425                         yaffsfs_SetError(retVal);
1426                         retVal = -1;
1427                 }
1428         }
1429
1430         yaffsfs_Unlock();
1431
1432         return retVal;
1433
1434 }
1435
1436 int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1437 {
1438         return yaffs_do_setxattr(path, name, data, size, flags, 1);
1439 }
1440
1441 int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1442 {
1443         return yaffs_do_setxattr(path, name, data, size, flags, 0);
1444 }
1445
1446
1447
1448 int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
1449 {
1450         struct yaffs_obj *obj;
1451
1452         int retVal = -1;
1453
1454         yaffsfs_Lock();
1455         obj = yaffsfs_GetHandleObject(fd);
1456
1457         if(!obj) 
1458                 yaffsfs_SetError(-EBADF);
1459         else {
1460                 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1461                 if(retVal< 0){
1462                         yaffsfs_SetError(retVal);
1463                         retVal = -1;
1464                 }
1465         }
1466
1467         yaffsfs_Unlock();
1468
1469         return retVal;
1470 }
1471
1472 static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
1473 {
1474         struct yaffs_obj *obj;
1475         struct yaffs_obj *dir;
1476
1477         int retVal = -1;
1478
1479         if(yaffsfs_CheckPath(path) < 0){
1480                 yaffsfs_SetError(-ENAMETOOLONG);
1481                 return -1;
1482         }
1483
1484         yaffsfs_Lock();
1485
1486         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1487
1488         if(follow)
1489                 obj = yaffsfs_FollowLink(obj,0);
1490
1491         if(!dir) 
1492                 yaffsfs_SetError(-ENOTDIR);
1493         else if(!obj) 
1494                 yaffsfs_SetError(-ENOENT);
1495         else {
1496                 retVal = yaffs_get_xattrib(obj,name,data,size);
1497                 if(retVal< 0){
1498                         yaffsfs_SetError(retVal);
1499                         retVal = -1;
1500                 }
1501         }
1502         yaffsfs_Unlock();
1503
1504         return retVal;
1505
1506 }
1507
1508 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1509 {
1510         return yaffs_do_getxattr( path, name, data, size, 1);
1511 }
1512 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1513 {
1514         return yaffs_do_getxattr( path, name, data, size, 0);
1515 }
1516
1517
1518
1519 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1520 {
1521         struct yaffs_obj *obj;
1522
1523         int retVal = -1;
1524
1525         yaffsfs_Lock();
1526         obj = yaffsfs_GetHandleObject(fd);
1527
1528         if(obj) {
1529                 retVal = yaffs_get_xattrib(obj,name,data,size);
1530                 if(retVal< 0){
1531                         yaffsfs_SetError(retVal);
1532                         retVal = -1;
1533                 }
1534         } else
1535                 /* bad handle */
1536                 yaffsfs_SetError(-EBADF);
1537
1538         yaffsfs_Unlock();
1539
1540         return retVal;
1541 }
1542
1543 static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
1544 {
1545         struct yaffs_obj *obj=NULL;
1546         struct yaffs_obj *dir=NULL;
1547
1548         int retVal = -1;
1549
1550         if(yaffsfs_CheckPath(path) < 0){
1551                 yaffsfs_SetError(-ENAMETOOLONG);
1552                 return -1;
1553         }
1554
1555         yaffsfs_Lock();
1556
1557         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1558
1559         if(follow)
1560                 obj = yaffsfs_FollowLink(obj,0);
1561
1562         if(!dir) 
1563                 yaffsfs_SetError(-ENOTDIR);
1564         else if(!obj) 
1565                 yaffsfs_SetError(-ENOENT);
1566         else {
1567                 retVal = yaffs_list_xattrib(obj, data,size);
1568                 if(retVal< 0){
1569                         yaffsfs_SetError(retVal);
1570                         retVal = -1;
1571                 }
1572         }
1573
1574         yaffsfs_Unlock();
1575
1576         return retVal;
1577
1578 }
1579
1580 int yaffs_listxattr(const YCHAR *path, char *data, int size)
1581 {
1582         return yaffs_do_listxattr(path, data, size, 1);
1583 }
1584
1585 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
1586 {
1587         return yaffs_do_listxattr(path, data, size, 0);
1588 }
1589
1590 int yaffs_flistxattr(int fd, char *data, int size)
1591 {
1592         struct yaffs_obj *obj;
1593
1594         int retVal = -1;
1595
1596         yaffsfs_Lock();
1597         obj = yaffsfs_GetHandleObject(fd);
1598
1599         if(obj) {
1600                 retVal = yaffs_list_xattrib(obj,data,size);
1601                 if(retVal< 0){
1602                         yaffsfs_SetError(retVal);
1603                         retVal = -1;
1604                 }
1605         } else
1606                 /* bad handle */
1607                 yaffsfs_SetError(-EBADF);
1608
1609         yaffsfs_Unlock();
1610
1611         return retVal;
1612 }
1613
1614 static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
1615 {
1616         struct yaffs_obj *obj=NULL;
1617         struct yaffs_obj *dir=NULL;
1618
1619         int retVal = -1;
1620
1621         if(yaffsfs_CheckPath(path) < 0){
1622                 yaffsfs_SetError(-ENAMETOOLONG);
1623                 return -1;
1624         }
1625
1626         yaffsfs_Lock();
1627
1628         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1629
1630         if(follow)
1631                 obj = yaffsfs_FollowLink(obj,0);
1632
1633         if(!dir) 
1634                 yaffsfs_SetError(-ENOTDIR);
1635         else if(!obj) 
1636                 yaffsfs_SetError(-ENOENT);
1637         else {
1638                 retVal = yaffs_remove_xattrib(obj,name);
1639                 if(retVal< 0){
1640                         yaffsfs_SetError(retVal);
1641                         retVal = -1;
1642                 }
1643         }
1644
1645         yaffsfs_Unlock();
1646
1647         return retVal;
1648
1649 }
1650
1651 int yaffs_removexattr(const YCHAR *path, const char *name)
1652 {
1653         return yaffs_do_removexattr(path, name, 1);
1654 }
1655
1656 int yaffs_lremovexattr(const YCHAR *path, const char *name)
1657 {
1658         return yaffs_do_removexattr(path, name, 0);
1659 }
1660
1661 int yaffs_fremovexattr(int fd, const char *name)
1662 {
1663         struct yaffs_obj *obj;
1664
1665         int retVal = -1;
1666
1667         yaffsfs_Lock();
1668         obj = yaffsfs_GetHandleObject(fd);
1669
1670         if(obj){
1671                 retVal = yaffs_remove_xattrib(obj,name);
1672                 if(retVal< 0){
1673                         yaffsfs_SetError(retVal);
1674                         retVal = -1;
1675                 }
1676         }else
1677                 /* bad handle */
1678                 yaffsfs_SetError(-EBADF);
1679
1680         yaffsfs_Unlock();
1681
1682         return retVal;
1683 }
1684 #endif
1685
1686 #ifdef CONFIG_YAFFS_WINCE
1687 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1688 {
1689         struct yaffs_obj *obj;
1690
1691         int retVal = -1;
1692
1693         yaffsfs_Lock();
1694         obj = yaffsfs_GetHandleObject(fd);
1695
1696         if(obj){
1697
1698                 if(wctime){
1699                         wctime[0] = obj->win_ctime[0];
1700                         wctime[1] = obj->win_ctime[1];
1701                 }
1702                 if(watime){
1703                         watime[0] = obj->win_atime[0];
1704                         watime[1] = obj->win_atime[1];
1705                 }
1706                 if(wmtime){
1707                         wmtime[0] = obj->win_mtime[0];
1708                         wmtime[1] = obj->win_mtime[1];
1709                 }
1710
1711
1712                 retVal = 0;
1713         } else
1714                 /*  bad handle */
1715                 yaffsfs_SetError(-EBADF);               
1716         
1717         yaffsfs_Unlock();
1718         
1719         return retVal;
1720 }
1721
1722
1723 int yaffs_set_wince_times(int fd, 
1724                                                   const unsigned *wctime, 
1725                                                   const unsigned *watime, 
1726                                                   const unsigned *wmtime)
1727 {
1728         struct yaffs_obj *obj;
1729         int result;
1730         int retVal = -1;
1731
1732         yaffsfs_Lock();
1733         obj = yaffsfs_GetHandleObject(fd);
1734
1735         if(obj){
1736
1737                 if(wctime){
1738                         obj->win_ctime[0] = wctime[0];
1739                         obj->win_ctime[1] = wctime[1];
1740                 }
1741                 if(watime){
1742                         obj->win_atime[0] = watime[0];
1743                         obj->win_atime[1] = watime[1];
1744                 }
1745                 if(wmtime){
1746                         obj->win_mtime[0] = wmtime[0];
1747                         obj->win_mtime[1] = wmtime[1];
1748                 }
1749
1750                 obj->dirty = 1;
1751                 result = yaffs_flush_file(obj,0,0);
1752                 retVal = 0;
1753         } else
1754                 /* bad handle */
1755                 yaffsfs_SetError(-EBADF);
1756
1757         yaffsfs_Unlock();
1758
1759         return retVal;
1760 }
1761
1762 #endif
1763
1764
1765 static int yaffsfs_DoChMod(struct yaffs_obj *obj,mode_t mode)
1766 {
1767         int result = -1;
1768
1769         if(obj)
1770                 obj = yaffs_get_equivalent_obj(obj);
1771
1772         if(obj) {
1773                 obj->yst_mode = mode;
1774                 obj->dirty = 1;
1775                 result = yaffs_flush_file(obj,0,0);
1776         }
1777
1778         return result == YAFFS_OK ? 0 : -1;
1779 }
1780
1781
1782 int yaffs_access(const YCHAR *path, int amode)
1783 {
1784         struct yaffs_obj *obj=NULL;
1785         struct yaffs_obj *dir=NULL;
1786
1787         int retval = -1;
1788
1789         if(yaffsfs_CheckPath(path) < 0){
1790                 yaffsfs_SetError(-ENAMETOOLONG);
1791                 return -1;
1792         }
1793
1794         if(amode & ~(R_OK | W_OK | X_OK)){
1795                 yaffsfs_SetError(-EINVAL);
1796                 return -1;
1797         }
1798
1799         yaffsfs_Lock();
1800
1801         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1802
1803         if(!dir) 
1804                 yaffsfs_SetError(-ENOTDIR);
1805         else if(!obj) 
1806                 yaffsfs_SetError(-ENOENT);
1807         else {
1808                 int access_ok = 1;
1809
1810                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1811                         access_ok = 0;
1812                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1813                         access_ok = 0;
1814                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1815                         access_ok = 0;
1816
1817                 if(!access_ok)
1818                         yaffsfs_SetError(-EACCES);
1819                 else
1820                         retval = 0;
1821         }
1822
1823         yaffsfs_Unlock();
1824
1825         return retval;
1826
1827 }
1828
1829
1830 int yaffs_chmod(const YCHAR *path, mode_t mode)
1831 {
1832         struct yaffs_obj *obj=NULL;
1833         struct yaffs_obj *dir=NULL;
1834         int retVal = -1;
1835
1836         if(yaffsfs_CheckPath(path) < 0){
1837                 yaffsfs_SetError(-ENAMETOOLONG);
1838                 return -1;
1839         }
1840
1841         if(mode & ~(0777)){
1842                 yaffsfs_SetError(-EINVAL);
1843                 return -1;
1844         }
1845
1846         yaffsfs_Lock();
1847
1848         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1849
1850         if(!dir) 
1851                 yaffsfs_SetError(-ENOTDIR);
1852         else if(!obj) 
1853                 yaffsfs_SetError(-ENOENT);
1854         else if(obj->my_dev->read_only)
1855                 yaffsfs_SetError(-EROFS);
1856         else
1857                 retVal = yaffsfs_DoChMod(obj,mode);
1858
1859         yaffsfs_Unlock();
1860
1861         return retVal;
1862
1863 }
1864
1865
1866 int yaffs_fchmod(int fd, mode_t mode)
1867 {
1868         struct yaffs_obj *obj;
1869         int retVal = -1;
1870
1871         if(mode & ~(0777)){
1872                 yaffsfs_SetError(-EINVAL);
1873                 return -1;
1874         }
1875
1876         yaffsfs_Lock();
1877         obj = yaffsfs_GetHandleObject(fd);
1878
1879         if(!obj)
1880                 yaffsfs_SetError(-EBADF);
1881         else if(obj->my_dev->read_only)
1882                 yaffsfs_SetError(-EROFS);
1883         else
1884                 retVal = yaffsfs_DoChMod(obj,mode);
1885
1886         yaffsfs_Unlock();
1887
1888         return retVal;
1889 }
1890
1891
1892 static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path)
1893 {
1894         YCHAR *alt_path = NULL;
1895         int path_length;
1896         int i;
1897
1898         /*
1899          * We don't have a definition for max path length.
1900          * We will use 3 * max name length instead.
1901          */
1902         *ret_path = NULL;
1903         path_length = strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1);
1904
1905         /* If the last character is a path divider, then we need to
1906          * trim it back so that the name look-up works properly.
1907          * eg. /foo/new_dir/ -> /foo/newdir
1908          * Curveball: Need to handle multiple path dividers:
1909          * eg. /foof/sdfse///// -> /foo/sdfse
1910          */
1911         if(path_length > 0 && 
1912                 yaffsfs_IsPathDivider(path[path_length-1])){
1913                 alt_path = YMALLOC(path_length + 1);
1914                 if(!alt_path)
1915                         return -1;
1916                 strcpy(alt_path, path);
1917                 for(i = path_length-1;
1918                         i >= 0 && yaffsfs_IsPathDivider(alt_path[i]);
1919                         i--)
1920                         alt_path[i] = (YCHAR) 0;
1921         }
1922         *ret_path = alt_path;
1923         return 0;
1924 }
1925
1926 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1927 {
1928         struct yaffs_obj *parent = NULL;
1929         struct yaffs_obj *dir = NULL;
1930         YCHAR *name;
1931         YCHAR *alt_path = NULL;
1932         int retVal= -1;
1933
1934         if(yaffsfs_CheckPath(path) < 0){
1935                 yaffsfs_SetError(-ENAMETOOLONG);
1936                 return -1;
1937         }
1938
1939         if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
1940                 yaffsfs_SetError(-ENOMEM);
1941                 return -1;
1942         }
1943         if(alt_path)
1944                 path = alt_path;
1945         
1946         yaffsfs_Lock();
1947         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1948         if(!parent)
1949                 yaffsfs_SetError(-ENOTDIR);
1950         else if(parent && yaffs_strnlen(name,5) == 0){
1951                 /* Trying to make the root itself */
1952                 yaffsfs_SetError(-EEXIST);
1953         } else if(parent && parent->my_dev->read_only)
1954                 yaffsfs_SetError(-EROFS);
1955         else {
1956                 dir = yaffs_create_dir(parent,name,mode,0,0);
1957                 if(dir)
1958                         retVal = 0;
1959                 else if (yaffs_find_by_name(parent,name))
1960                         yaffsfs_SetError(-EEXIST); /* the name already exists */
1961                 else
1962                         yaffsfs_SetError(-ENOSPC); /* just assume no space */
1963         }
1964
1965         yaffsfs_Unlock();
1966
1967         if(alt_path)
1968                 YFREE(alt_path);
1969
1970         return retVal;
1971 }
1972
1973 int yaffs_rmdir(const YCHAR *path)
1974 {
1975         int result;
1976         YCHAR *alt_path;
1977
1978         if(yaffsfs_CheckPath(path) < 0){
1979                 yaffsfs_SetError(-ENAMETOOLONG);
1980                 return -1;
1981         }
1982
1983         if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
1984                 yaffsfs_SetError(-ENOMEM);
1985                 return -1;
1986         }
1987         if(alt_path)
1988                 path = alt_path;
1989         result =  yaffsfs_DoUnlink(path,1);
1990         if(alt_path)
1991                 YFREE(alt_path);
1992         return result;
1993 }
1994
1995
1996 void * yaffs_getdev(const YCHAR *path)
1997 {
1998         struct yaffs_dev *dev=NULL;
1999         YCHAR *dummy;
2000         dev = yaffsfs_FindDevice(path,&dummy);
2001         return (void *)dev;
2002 }
2003
2004 int yaffs_mount2(const YCHAR *path,int read_only)
2005 {
2006         int retVal=-1;
2007         int result=YAFFS_FAIL;
2008         struct yaffs_dev *dev=NULL;
2009
2010         T(YAFFS_TRACE_MOUNT,(TSTR("yaffs: Mounting %s" TENDSTR),path));
2011
2012         if(yaffsfs_CheckPath(path) < 0){
2013                 yaffsfs_SetError(-ENAMETOOLONG);
2014                 return -1;
2015         }
2016
2017         yaffsfs_Lock();
2018
2019         yaffsfs_InitHandles();
2020
2021         dev = yaffsfs_FindMountPoint(path);
2022         if(dev){
2023                 if(!dev->is_mounted){
2024                         dev->read_only = read_only ? 1 : 0;
2025                         result = yaffs_guts_initialise(dev);
2026                         if(result == YAFFS_FAIL)
2027                                 /* todo error - mount failed */
2028                                 yaffsfs_SetError(-ENOMEM);
2029                         retVal = result ? 0 : -1;
2030
2031                 }
2032                 else
2033                         /* todo error - already mounted. */
2034                         yaffsfs_SetError(-EBUSY);
2035         } else
2036                 /* todo error - no device */
2037                 yaffsfs_SetError(-ENODEV);
2038
2039         yaffsfs_Unlock();
2040         return retVal;
2041
2042 }
2043
2044 int yaffs_mount(const YCHAR *path)
2045 {
2046         return yaffs_mount2(path,0);
2047 }
2048
2049 int yaffs_sync(const YCHAR *path)
2050 {
2051         int retVal=-1;
2052         struct yaffs_dev *dev=NULL;
2053         YCHAR *dummy;
2054
2055         if(yaffsfs_CheckPath(path) < 0){
2056                 yaffsfs_SetError(-ENAMETOOLONG);
2057                 return -1;
2058         }
2059         
2060         yaffsfs_Lock();
2061         dev = yaffsfs_FindDevice(path,&dummy);
2062         if(dev){
2063                 if(dev->is_mounted){
2064                         
2065                         yaffs_flush_whole_cache(dev);
2066                         yaffs_checkpoint_save(dev);
2067                         retVal = 0;
2068                         
2069                 } else
2070                         /* todo error - not mounted. */
2071                         yaffsfs_SetError(-EINVAL);
2072                         
2073         }else
2074                 /* todo error - no device */
2075                 yaffsfs_SetError(-ENODEV);
2076
2077         yaffsfs_Unlock();
2078         return retVal;  
2079 }
2080
2081
2082 int yaffs_remount(const YCHAR *path, int force, int read_only)
2083 {
2084         int retVal=-1;
2085         struct yaffs_dev *dev=NULL;
2086         yaffsfs_Handle *yh;
2087
2088         if(yaffsfs_CheckPath(path) < 0){
2089                 yaffsfs_SetError(-ENAMETOOLONG);
2090                 return -1;
2091         }
2092
2093         yaffsfs_Lock();
2094         dev = yaffsfs_FindMountPoint(path);
2095         if(dev){
2096                 if(dev->is_mounted){
2097                         int i;
2098                         int inUse;
2099
2100                         yaffs_flush_whole_cache(dev);
2101
2102                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
2103                                 yh = & yaffsfs_handle[i];
2104                                 if(yh->useCount>0 && 
2105                                         yaffsfs_inode[yh->inodeId].iObj->my_dev == dev)
2106                                         inUse = 1; /* the device is in use, can't unmount */
2107                         }
2108
2109                         if(!inUse || force){
2110                                 if(read_only)
2111                                         yaffs_checkpoint_save(dev);
2112                                 dev->read_only =  read_only ? 1 : 0;
2113                                 retVal = 0;
2114                         } else
2115                                 yaffsfs_SetError(-EBUSY);
2116
2117                 } else
2118                         yaffsfs_SetError(-EINVAL);
2119
2120         }
2121         else
2122                 yaffsfs_SetError(-ENODEV);
2123
2124         yaffsfs_Unlock();
2125         return retVal;
2126
2127 }
2128
2129 int yaffs_unmount2(const YCHAR *path, int force)
2130 {
2131         int retVal=-1;
2132         struct yaffs_dev *dev=NULL;
2133
2134         if(yaffsfs_CheckPath(path) < 0){
2135                 yaffsfs_SetError(-ENAMETOOLONG);
2136                 return -1;
2137         }
2138
2139         yaffsfs_Lock();
2140         dev = yaffsfs_FindMountPoint(path);
2141         if(dev){
2142                 if(dev->is_mounted){
2143                         int i;
2144                         int inUse;
2145
2146                         yaffs_flush_whole_cache(dev);
2147                         yaffs_checkpoint_save(dev);
2148
2149                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
2150                                 if(yaffsfs_handle[i].useCount > 0 && 
2151                                 yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->my_dev == dev)
2152                                         inUse = 1; /* the device is in use, can't unmount */
2153                         }
2154
2155                         if(!inUse || force){
2156                                 if(inUse)
2157                                         yaffsfs_PutDeviceHandles(dev);
2158                                 yaffs_deinitialise(dev);
2159
2160                                 retVal = 0;
2161                         } else
2162                                 /* todo error can't unmount as files are open */
2163                                 yaffsfs_SetError(-EBUSY);
2164
2165                 } else
2166                         /* todo error - not mounted. */
2167                         yaffsfs_SetError(-EINVAL);
2168
2169         } else
2170                 /* todo error - no device */
2171                 yaffsfs_SetError(-ENODEV);
2172
2173         yaffsfs_Unlock();
2174         return retVal;
2175
2176 }
2177
2178 int yaffs_unmount(const YCHAR *path)
2179 {
2180         return yaffs_unmount2(path,0);
2181 }
2182
2183 loff_t yaffs_freespace(const YCHAR *path)
2184 {
2185         loff_t retVal=-1;
2186         struct yaffs_dev *dev=NULL;
2187         YCHAR *dummy;
2188
2189         if(yaffsfs_CheckPath(path) < 0){
2190                 yaffsfs_SetError(-ENAMETOOLONG);
2191                 return -1;
2192         }
2193
2194         yaffsfs_Lock();
2195         dev = yaffsfs_FindDevice(path,&dummy);
2196         if(dev  && dev->is_mounted){
2197                 retVal = yaffs_get_n_free_chunks(dev);
2198                 retVal *= dev->data_bytes_per_chunk;
2199
2200         } else
2201                 yaffsfs_SetError(-EINVAL);
2202
2203         yaffsfs_Unlock();
2204         return retVal;
2205 }
2206
2207 loff_t yaffs_totalspace(const YCHAR *path)
2208 {
2209         loff_t retVal=-1;
2210         struct yaffs_dev *dev=NULL;
2211         YCHAR *dummy;
2212
2213         if(yaffsfs_CheckPath(path) < 0){
2214                 yaffsfs_SetError(-ENAMETOOLONG);
2215                 return -1;
2216         }
2217
2218         yaffsfs_Lock();
2219         dev = yaffsfs_FindDevice(path,&dummy);
2220         if(dev  && dev->is_mounted){
2221                 retVal = (dev->param.end_block - dev->param.start_block + 1) - 
2222                         dev->param.n_reserved_blocks;
2223                 retVal *= dev->param.chunks_per_block;
2224                 retVal *= dev->data_bytes_per_chunk;
2225
2226         } else
2227                 yaffsfs_SetError(-EINVAL);
2228
2229         yaffsfs_Unlock();
2230         return retVal;
2231 }
2232
2233 int yaffs_inodecount(const YCHAR *path)
2234 {
2235         loff_t retVal= -1;
2236         struct yaffs_dev *dev=NULL;
2237         YCHAR *dummy;
2238
2239         if(yaffsfs_CheckPath(path) < 0){
2240                 yaffsfs_SetError(-ENAMETOOLONG);
2241                 return -1;
2242         }
2243
2244         yaffsfs_Lock();
2245         dev = yaffsfs_FindDevice(path,&dummy);
2246         if(dev  && dev->is_mounted) {
2247            int n_obj = dev->n_obj;
2248            if(n_obj > dev->n_hardlinks)
2249                 retVal = n_obj - dev->n_hardlinks;
2250         }
2251         
2252         if(retVal < 0)
2253                 yaffsfs_SetError(-EINVAL);
2254         
2255         yaffsfs_Unlock();
2256         return retVal;  
2257 }
2258
2259
2260 void yaffs_add_device(struct yaffs_dev *dev)
2261 {
2262         dev->is_mounted = 0;
2263         dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
2264
2265         if(!dev->dev_list.next)
2266                 INIT_LIST_HEAD(&dev->dev_list);
2267
2268         list_add(&dev->dev_list,&yaffsfs_deviceList);
2269 }
2270
2271 void yaffs_remove_device(struct yaffs_dev *dev)
2272 {
2273         list_del_init(&dev->dev_list);
2274 }
2275
2276
2277
2278
2279 /* Directory search stuff. */
2280
2281 /*
2282  * Directory search context
2283  *
2284  * NB this is an opaque structure.
2285  */
2286
2287
2288 typedef struct
2289 {
2290         u32 magic;
2291         yaffs_dirent de;                /* directory entry being used by this dsc */
2292         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
2293         struct yaffs_obj *dirObj;           /* ptr to directory being searched */
2294         struct yaffs_obj *nextReturn;       /* obj to be returned by next readddir */
2295         int offset;
2296         struct list_head others;       
2297 } yaffsfs_DirectorySearchContext;
2298
2299
2300
2301 static struct list_head search_contexts;
2302
2303
2304 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
2305 {
2306         if(dsc &&
2307            dsc->dirObj &&
2308            dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2309
2310            dsc->offset = 0;
2311
2312            if( list_empty(&dsc->dirObj->variant.dir_variant.children))
2313                 dsc->nextReturn = NULL;
2314            else
2315                 dsc->nextReturn = list_entry(dsc->dirObj->variant.dir_variant.children.next,
2316                                                 struct yaffs_obj,siblings);
2317         } else {
2318                 /* Hey someone isn't playing nice! */
2319         }
2320 }
2321
2322 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
2323 {
2324         if(dsc &&
2325            dsc->dirObj &&
2326            dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2327
2328            if( dsc->nextReturn == NULL ||
2329                list_empty(&dsc->dirObj->variant.dir_variant.children))
2330                 dsc->nextReturn = NULL;
2331            else {
2332                    struct list_head *next = dsc->nextReturn->siblings.next;
2333
2334                    if( next == &dsc->dirObj->variant.dir_variant.children)
2335                         dsc->nextReturn = NULL; /* end of list */
2336                    else
2337                         dsc->nextReturn = list_entry(next,struct yaffs_obj,siblings);
2338            }
2339         } else {
2340                 /* Hey someone isn't playing nice! */
2341         }
2342 }
2343
2344 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
2345 {
2346
2347         struct list_head *i;
2348         yaffsfs_DirectorySearchContext *dsc;
2349
2350         /* if search contexts not initilised then skip */
2351         if(!search_contexts.next)
2352                 return;
2353
2354         /* Iterate through the directory search contexts.
2355          * If any are the one being removed, then advance the dsc to
2356          * the next one to prevent a hanging ptr.
2357          */
2358          list_for_each(i, &search_contexts) {
2359                 if (i) {
2360                         dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
2361                         if(dsc->nextReturn == obj)
2362                                 yaffsfs_DirAdvance(dsc);
2363                 }
2364         }
2365
2366 }
2367
2368 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
2369 {
2370         yaffs_DIR *dir = NULL;
2371         struct yaffs_obj *obj = NULL;
2372         yaffsfs_DirectorySearchContext *dsc = NULL;
2373
2374         if(yaffsfs_CheckPath(dirname) < 0){
2375                 yaffsfs_SetError(-ENAMETOOLONG);
2376                 return -1;
2377         }
2378
2379         yaffsfs_Lock();
2380
2381         obj = yaffsfs_FindObject(NULL,dirname,0,1,NULL);
2382
2383         if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2384
2385                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
2386                 dir = (yaffs_DIR *)dsc;
2387
2388                 if(dsc){
2389                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
2390                         dsc->magic = YAFFS_MAGIC;
2391                         dsc->dirObj = obj;
2392                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
2393                         INIT_LIST_HEAD(&dsc->others);
2394
2395                         if(!search_contexts.next)
2396                                 INIT_LIST_HEAD(&search_contexts);
2397
2398                         list_add(&dsc->others,&search_contexts);       
2399                         yaffsfs_SetDirRewound(dsc);
2400                 }
2401
2402         }
2403
2404         yaffsfs_Unlock();
2405
2406         return dir;
2407 }
2408
2409 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2410 {
2411         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2412         struct yaffs_dirent *retVal = NULL;
2413
2414         yaffsfs_Lock();
2415
2416         if(dsc && dsc->magic == YAFFS_MAGIC){
2417                 yaffsfs_SetError(0);
2418                 if(dsc->nextReturn){
2419                         dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
2420                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2421                         dsc->de.d_off = dsc->offset++;
2422                         yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2423                         if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2424                         {
2425                                 /* this should not happen! */
2426                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2427                         }
2428                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2429                         retVal = &dsc->de;
2430                         yaffsfs_DirAdvance(dsc);
2431                 } else
2432                         retVal = NULL;
2433         } else
2434                 yaffsfs_SetError(-EBADF);
2435
2436         yaffsfs_Unlock();
2437
2438         return retVal;
2439
2440 }
2441
2442
2443 void yaffs_rewinddir(yaffs_DIR *dirp)
2444 {
2445         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2446
2447         yaffsfs_Lock();
2448
2449         yaffsfs_SetDirRewound(dsc);
2450
2451         yaffsfs_Unlock();
2452 }
2453
2454
2455 int yaffs_closedir(yaffs_DIR *dirp)
2456 {
2457         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2458
2459         yaffsfs_Lock();
2460         dsc->magic = 0;
2461         list_del(&dsc->others); /* unhook from list */
2462         YFREE(dsc);
2463         yaffsfs_Unlock();
2464         return 0;
2465 }
2466
2467 /* End of directory stuff */
2468
2469
2470 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2471 {
2472         struct yaffs_obj *parent = NULL;
2473         struct yaffs_obj *obj;
2474         YCHAR *name;
2475         int retVal= -1;
2476         int mode = 0; /* ignore for now */
2477
2478         if(yaffsfs_CheckPath(newpath) < 0){
2479                 yaffsfs_SetError(-ENAMETOOLONG);
2480                 return -1;
2481         }
2482         yaffsfs_Lock();
2483         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
2484         if(!parent)
2485                 yaffsfs_SetError(-ENOTDIR);
2486         else if( strlen(name) < 1)
2487                 yaffsfs_SetError(-ENOENT);
2488         else if(parent->my_dev->read_only)
2489                 yaffsfs_SetError(-EROFS);
2490         else if(parent){
2491                 obj = yaffs_create_symlink(parent,name,mode,0,0,oldpath);
2492                 if(obj)
2493                         retVal = 0;
2494                 else{
2495                         yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
2496                         retVal = -1;
2497                 }
2498         }
2499
2500         yaffsfs_Unlock();
2501
2502         return retVal;
2503
2504 }
2505
2506 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
2507 {
2508         struct yaffs_obj *obj = NULL;
2509         struct yaffs_obj *dir = NULL;
2510         int retVal= -1;
2511
2512         yaffsfs_Lock();
2513
2514         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
2515
2516         if(!dir) 
2517                 yaffsfs_SetError(-ENOTDIR);
2518         else if(!obj) 
2519                 yaffsfs_SetError(-ENOENT);
2520         else if(obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
2521                 yaffsfs_SetError(-EINVAL);
2522         else {
2523                 YCHAR *alias = obj->variant.symlink_variant.alias;
2524                 memset(buf,0,bufsiz);
2525                 yaffs_strncpy(buf,alias,bufsiz - 1);
2526                 retVal = 0;
2527         }
2528         yaffsfs_Unlock();
2529         return retVal;
2530 }
2531
2532 int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
2533 {
2534         /* Creates a link called newpath to existing oldpath */
2535         struct yaffs_obj *obj = NULL;
2536         struct yaffs_obj *lnk = NULL;
2537         int retVal = -1;
2538
2539         if(yaffsfs_CheckPath(linkpath) < 0){
2540                 yaffsfs_SetError(-ENAMETOOLONG);
2541                 return -1;
2542         }
2543
2544         yaffsfs_Lock();
2545
2546         obj = yaffsfs_FindObject(NULL,oldpath,0,1,NULL);
2547         lnk = yaffsfs_FindObject(NULL,linkpath,0,0,NULL);
2548
2549         if(!obj)
2550                 yaffsfs_SetError(-ENOENT);
2551         else if(obj->my_dev->read_only)
2552                 yaffsfs_SetError(-EINVAL);
2553         else if(lnk)
2554                 yaffsfs_SetError(-EEXIST);
2555         else {
2556                 struct yaffs_obj *newdir = NULL;
2557                 struct yaffs_obj *link = NULL;
2558
2559                 YCHAR *newname;
2560
2561                 newdir = yaffsfs_FindDirectory(NULL,linkpath,&newname,0);
2562
2563                 if(!newdir)
2564                         yaffsfs_SetError(-ENOTDIR);
2565                 else if(newdir->my_dev != obj->my_dev)
2566                         yaffsfs_SetError(-EXDEV);
2567                 
2568                 retVal = yaffsfs_CheckNameLength(newname);
2569                 
2570                 if(retVal == 0) {
2571                         link = yaffs_link_obj(newdir,newname,obj);
2572                         if(link)
2573                                 retVal = 0;
2574                         else{
2575                                 yaffsfs_SetError(-ENOSPC);
2576                                 retVal = -1;
2577                         }
2578
2579                 }
2580         }
2581         yaffsfs_Unlock();
2582
2583         return retVal;
2584 }
2585
2586 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
2587 {
2588         pathname=pathname;
2589         mode=mode;
2590         dev=dev;
2591
2592         yaffsfs_SetError(-EINVAL);
2593         return -1;
2594 }
2595
2596
2597
2598 /*
2599  * yaffs_n_handles()
2600  * Returns number of handles attached to the object
2601  */
2602 int yaffs_n_handles(const YCHAR *path)
2603 {
2604         struct yaffs_obj *obj;
2605
2606         if(yaffsfs_CheckPath(path) < 0){
2607                 yaffsfs_SetError(-ENAMETOOLONG);
2608                 return -1;
2609         }
2610
2611         obj = yaffsfs_FindObject(NULL,path,0,1,NULL);
2612
2613         if(obj)
2614                 return yaffsfs_CountHandles(obj);
2615         else
2616                 return -1;
2617 }
2618
2619 int yaffs_get_error(void)
2620 {
2621         return yaffsfs_GetLastError();
2622 }
2623
2624 int yaffs_set_error(int error)
2625 {
2626         /*yaffsfs_SetError does not return. So the program is assumed to have worked. */
2627         yaffsfs_SetError(error);
2628         return 0;
2629 }
2630
2631 int yaffs_dump_dev(const YCHAR *path)
2632 {
2633 #if 1
2634         path=path;
2635 #else
2636         YCHAR *rest;
2637
2638         struct yaffs_obj *obj = yaffsfs_FindRoot(path,&rest);
2639
2640         if(obj){
2641                 struct yaffs_dev *dev = obj->my_dev;
2642
2643                 printf("\n"
2644                            "n_page_writes.......... %d\n"
2645                            "n_page_reads........... %d\n"
2646                            "n_erasures....... %d\n"
2647                            "n_gc_copies............ %d\n"
2648                            "garbageCollections... %d\n"
2649                            "passiveGarbageColl'ns %d\n"
2650                            "\n",
2651                                 dev->n_page_writes,
2652                                 dev->n_page_reads,
2653                                 dev->n_erasures,
2654                                 dev->n_gc_copies,
2655                                 dev->garbageCollections,
2656                                 dev->passiveGarbageCollections
2657                 );
2658
2659         }
2660
2661 #endif
2662         return 0;
2663 }
2664