yaffs direct: Fix yaffs_mkdir error paths
[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 /* FindMountPoint only returns a dev entry if the path is a mount point */
417 static struct yaffs_dev *yaffsfs_FindMountPoint(const YCHAR *path)
418 {
419         struct yaffs_dev *dev;
420         YCHAR *restOfPath=NULL;
421         dev = yaffsfs_FindDevice(path,&restOfPath);
422         if(dev && restOfPath && *restOfPath)
423                 dev = NULL;
424         return dev;
425 }
426
427 static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath)
428 {
429
430         struct yaffs_dev *dev;
431
432         dev= yaffsfs_FindDevice(path,restOfPath);
433         if(dev && dev->is_mounted){
434                 return dev->root_dir;
435         }
436         return NULL;
437 }
438
439 static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj,int symDepth)
440 {
441
442         if(obj)
443                 obj = yaffs_get_equivalent_obj(obj);
444
445         while(obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){
446                 YCHAR *alias = obj->variant.symlink_variant.alias;
447
448                 if(yaffsfs_IsPathDivider(*alias))
449                         /* Starts with a /, need to scan from root up */
450                         obj = yaffsfs_FindObject(NULL,alias,symDepth++,1,NULL);
451                 else
452                         /* Relative to here, so use the parent of the symlink as a start */
453                         obj = yaffsfs_FindObject(obj->parent,alias,symDepth++,1,NULL);
454         }
455         return obj;
456 }
457
458
459 /*
460  * yaffsfs_FindDirectory
461  * Parse a path to determine the directory and the name within the directory.
462  *
463  * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
464  */
465 static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir,
466                                 const YCHAR *path, YCHAR **name, int symDepth)
467 {
468         struct yaffs_obj *dir;
469         YCHAR *restOfPath;
470         YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
471         int i;
472
473         if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
474                 return NULL;
475
476         if(startDir){
477                 dir = startDir;
478                 restOfPath = (YCHAR *)path;
479         }
480         else
481                 dir = yaffsfs_FindRoot(path,&restOfPath);
482
483         while(dir){
484                 /*
485                  * parse off /.
486                  * curve ball: also throw away surplus '/'
487                  * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
488                  */
489                 while(yaffsfs_IsPathDivider(*restOfPath))
490                         restOfPath++; /* get rid of '/' */
491
492                 *name = restOfPath;
493                 i = 0;
494
495                 while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)){
496                         if (i < YAFFS_MAX_NAME_LENGTH){
497                                 str[i] = *restOfPath;
498                                 str[i+1] = '\0';
499                                 i++;
500                         }
501                         restOfPath++;
502                 }
503
504                 if(!*restOfPath)
505                         /* got to the end of the string */
506                         return dir;
507                 else{
508                         if(yaffs_strcmp(str,_Y(".")) == 0)
509                         {
510                                 /* Do nothing */
511                         }
512                         else if(yaffs_strcmp(str,_Y("..")) == 0)
513                                 dir = dir->parent;
514                         else{
515                                 dir = yaffs_find_by_name(dir,str);
516
517                                 dir = yaffsfs_FollowLink(dir,symDepth);
518
519                                 if(dir && dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
520                                         dir = NULL;
521                         }
522                 }
523         }
524         /* directory did not exist. */
525         return NULL;
526 }
527
528 static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relativeDirectory,
529                                         const YCHAR *path,YCHAR **name,int symDepth)
530 {
531         return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
532 }
533
534 /*
535  * yaffsfs_FindObject turns a path for an existing object into the object
536  */
537 static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory,
538                         const YCHAR *path,int symDepth, int getEquiv,
539                         struct yaffs_obj **dirOut)
540 {
541         struct yaffs_obj *dir;
542         struct yaffs_obj *obj;
543         YCHAR *name;
544
545         dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
546
547         if(dirOut)
548                 *dirOut =  dir;
549
550         if(dir && *name)
551                 obj = yaffs_find_by_name(dir,name);
552         else
553                 obj = dir;
554
555         if(getEquiv)
556                 obj = yaffs_get_equivalent_obj(obj);
557
558         return obj;
559 }
560
561
562 int yaffs_dup(int fd)
563 {
564         int newHandle = -1;
565         yaffsfs_Handle *oldPtr = NULL;
566         yaffsfs_Handle *newPtr = NULL;
567
568         yaffsfs_Lock();
569
570         oldPtr = yaffsfs_GetHandlePointer(fd);
571         if(oldPtr && oldPtr->useCount > 0)
572                 newHandle = yaffsfs_GetNewHandle();
573         if(newHandle >= 0)
574                 newPtr = yaffsfs_GetHandlePointer(newHandle);
575
576         if(newPtr){
577                 *newPtr = *oldPtr;
578                 return newHandle;
579         }
580
581         if(!oldPtr)
582                 yaffsfs_SetError(-EBADF);
583         else
584                 yaffsfs_SetError(-ENOMEM);
585
586         return -1;
587
588 }
589
590
591
592 int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
593 {
594         struct yaffs_obj *obj = NULL;
595         struct yaffs_obj *dir = NULL;
596         YCHAR *name;
597         int handle = -1;
598         yaffsfs_Handle *yh = NULL;
599         int openDenied = 0;
600         int symDepth = 0;
601         int errorReported = 0;
602         int rwflags = oflag & ( O_RDWR | O_RDONLY | O_WRONLY);
603         u8 shareRead = (sharing & YAFFS_SHARE_READ) ?  1 : 0;
604         u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0;
605         u8 sharedReadAllowed;
606         u8 sharedWriteAllowed;
607         u8 alreadyReading;
608         u8 alreadyWriting;
609         u8 readRequested;
610         u8 writeRequested;
611
612         /* O_EXCL only has meaning if O_CREAT is specified */
613         if(!(oflag & O_CREAT))
614                 oflag &= ~(O_EXCL);
615
616         /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
617         if( (oflag & O_CREAT) & (oflag & O_EXCL))
618                 oflag &= ~(O_TRUNC);
619
620         /* Todo: Are there any more flag combos to sanitise ? */
621
622         /* Figure out if reading or writing is requested */
623
624         readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0;
625         writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0;
626
627         yaffsfs_Lock();
628
629         handle = yaffsfs_GetNewHandle();
630
631         if(handle < 0){
632                 yaffsfs_SetError(-ENFILE);
633                 errorReported = 1;
634         } else {
635
636                 yh = yaffsfs_GetHandlePointer(handle);
637
638                 /* try to find the exisiting object */
639                 obj = yaffsfs_FindObject(NULL,path,0,1,NULL);
640
641                 obj = yaffsfs_FollowLink(obj,symDepth++);
642
643                 if(obj &&
644                         obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
645                         obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
646                         obj = NULL;
647
648
649                 if(obj){
650
651                         /* The file already exists or it might be a directory */
652
653                         /* If it is a directory then we can't open it as a file */
654                         if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
655                                 openDenied = 1;
656                                 yaffsfs_SetError(-EISDIR);
657                                 errorReported = 1;
658                         }
659
660                         /* Open should fail if O_CREAT and O_EXCL are specified since
661                          * the file exists
662                          */
663                         if(!errorReported && (oflag & O_EXCL) && (oflag & O_CREAT)){
664                                 openDenied = 1;
665                                 yaffsfs_SetError(-EEXIST);
666                                 errorReported = 1;
667                         }
668
669                         /* Check file permissions */
670                         if( readRequested && !(obj->yst_mode & S_IREAD))
671                                 openDenied = 1;
672
673                         if( writeRequested && !(obj->yst_mode & S_IWRITE))
674                                 openDenied = 1;
675
676                         if(openDenied && !errorReported ) {
677                                 /* Error if the file exists but permissions are refused. */
678                                 yaffsfs_SetError(-EACCES);
679                                 errorReported = 1;
680                         }
681
682                         /* Check sharing of an existing object. */
683                         if(!openDenied){
684                                 yaffsfs_Handle *hx;
685                                 int i;
686                                 sharedReadAllowed = 1;
687                                 sharedWriteAllowed = 1;
688                                 alreadyReading = 0;
689                                 alreadyWriting = 0;
690                                 for( i = 0; i < YAFFSFS_N_HANDLES; i++){
691                                         hx = &yaffsfs_handle[i];
692                                         if(hx->useCount > 0 &&
693                                                 hx->inodeId >= 0 &&
694                                                 yaffsfs_inode[hx->inodeId].iObj == obj){
695                                                 if(!hx->shareRead)
696                                                         sharedReadAllowed = 0;
697                                                 if(!hx->shareWrite)
698                                                         sharedWriteAllowed = 0;
699                                                 if(hx->reading)
700                                                         alreadyReading = 1;
701                                                 if(hx->writing)
702                                                         alreadyWriting = 1;
703                                         }
704                                 }
705
706
707
708                                 if((!sharedReadAllowed && readRequested)|| 
709                                         (!shareRead  && alreadyReading) ||
710                                         (!sharedWriteAllowed && writeRequested) ||
711                                         (!shareWrite && alreadyWriting)){
712                                         openDenied = 1;
713                                         yaffsfs_SetError(-EBUSY);
714                                         errorReported=1;
715                                 }
716                         }
717
718                 }
719
720                 /* If we could not open an existing object, then let's see if
721                  * the directory exists. If not, error.
722                  */
723                 if(!obj && !errorReported){
724                         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
725                         if(!dir){
726                                 yaffsfs_SetError(-ENOTDIR);
727                                 errorReported = 1;
728                         }
729                 }
730
731                 if(!obj && dir && !errorReported && (oflag & O_CREAT)) {
732                         /* Let's see if we can create this file if it does not exist. */
733                         if(dir->my_dev->read_only){
734                                 yaffsfs_SetError(-EINVAL);
735                                 errorReported = 1;
736                         } else
737                                 obj = yaffs_create_file(dir,name,mode,0,0);
738
739                         if(!obj && !errorReported){
740                                 yaffsfs_SetError(-ENOSPC);
741                                 errorReported = 1;
742                         }
743                 }
744
745                 if(!obj && dir && !errorReported && !(oflag & O_CREAT)) {
746                         /* Error if the file does not exist and CREAT is not set. */
747                         yaffsfs_SetError(-ENOENT);
748                         errorReported = 1;
749                 }
750
751                 if(obj && !openDenied) {
752                         int inodeId = yaffsfs_GetInodeIdForObject(obj);
753
754                         if(inodeId<0) {
755                                 /*
756                                  * Todo: Fix any problem if inodes run out, though that
757                                  * can't happen if the number of inode items >= number of handles. 
758                                  */
759                         }
760                         
761                         yh->inodeId = inodeId;
762                         yh->reading = readRequested;
763                         yh->writing = writeRequested;
764                         yh->append =  (oflag & O_APPEND) ? 1 : 0;
765                         yh->position = 0;
766                         yh->shareRead = shareRead;
767                         yh->shareWrite = shareWrite;
768
769                         /* Hook inode to object */
770                         obj->my_inode = (void*) &yaffsfs_inode[inodeId];
771
772                         if((oflag & O_TRUNC) && yh->writing)
773                                 yaffs_resize_file(obj,0);
774                 } else {
775                         yaffsfs_PutHandle(handle);
776                         if(!errorReported) 
777                                 yaffsfs_SetError(0); /* Problem */
778                         handle = -1;
779                 }
780         }
781
782         yaffsfs_Unlock();
783
784         return handle;
785 }
786
787 int yaffs_open(const YCHAR *path, int oflag, int mode)
788 {
789         return yaffs_open_sharing(path, oflag, mode, YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
790 }
791
792 int yaffs_Dofsync(int fd,int datasync)
793 {
794         yaffsfs_Handle *h = NULL;
795         int retVal = 0;
796
797         yaffsfs_Lock();
798
799         h = yaffsfs_GetHandlePointer(fd);
800
801         if(h && h->useCount > 0)
802                 /* flush the file */
803                 yaffs_flush_file(yaffsfs_inode[h->inodeId].iObj,1,datasync);
804         else {
805                 /* bad handle */
806                 yaffsfs_SetError(-EBADF);
807                 retVal = -1;
808         }
809
810         yaffsfs_Unlock();
811
812         return retVal;
813 }
814
815 int yaffs_fsync(int fd)
816 {
817         return yaffs_Dofsync(fd,0);
818 }
819
820 int yaffs_flush(int fd)
821 {
822         return yaffs_fsync(fd);
823 }
824
825 int yaffs_fdatasync(int fd)
826 {
827         return yaffs_Dofsync(fd,1);
828 }
829
830 int yaffs_close(int fd)
831 {
832         yaffsfs_Handle *h = NULL;
833         int retVal = 0;
834
835         yaffsfs_Lock();
836
837         h = yaffsfs_GetHandlePointer(fd);
838
839         if(h && h->useCount > 0) {
840                 /* clean up */
841                 yaffs_flush_file(yaffsfs_inode[h->inodeId].iObj,1,0);
842                 yaffsfs_PutHandle(fd);
843                 retVal = 0;
844         } else {
845                 /* bad handle */
846                 yaffsfs_SetError(-EBADF);
847                 retVal = -1;
848         }
849
850         yaffsfs_Unlock();
851
852         return retVal;
853 }
854
855
856
857 int yaffsfs_do_read(int fd, void *vbuf, unsigned int nbyte, int isPread, int offset)
858 {
859         yaffsfs_Handle *h = NULL;
860         struct yaffs_obj *obj = NULL;
861         int pos = 0;
862         int startPos = 0;
863         int nRead = 0;
864         int nToRead = 0;
865         int totalRead = 0;
866         unsigned int maxRead;
867         u8 *buf = (u8 *)vbuf;
868
869         yaffsfs_Lock();
870         h = yaffsfs_GetHandlePointer(fd);
871         obj = yaffsfs_GetHandleObject(fd);
872
873         if(!h || !obj){
874                 /* bad handle */
875                 yaffsfs_SetError(-EBADF);
876                 totalRead = -1;
877         } else if(!h->reading){
878                 /* Not a reading handle */
879                 yaffsfs_SetError(-EINVAL);
880                 totalRead = -1;
881         } else {
882                 if(isPread)
883                         startPos = offset;
884                 else
885                         startPos = h->position;
886
887                 pos = startPos;
888                                         
889                 if(yaffs_get_obj_length(obj) > pos)
890                         maxRead = yaffs_get_obj_length(obj) - pos;
891                 else
892                         maxRead = 0;
893
894                 if(nbyte > maxRead)
895                         nbyte = maxRead;
896
897
898                 yaffsfs_GetHandle(fd);
899
900                 while(nbyte > 0) {
901                         nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
902                         if(nToRead > nbyte)
903                                 nToRead = nbyte;
904
905                         /* Tricky bit... 
906                          * Need to reverify object in case the device was
907                          * unmounted in another thread.
908                          */
909                         obj = yaffsfs_GetHandleObject(fd);
910                         if(!obj)
911                                 nRead = 0;
912                         else
913                                 nRead = yaffs_file_rd(obj,buf,pos,nToRead);
914
915                         if(nRead > 0){
916                                 totalRead += nRead;
917                                 pos += nRead;
918                                 buf += nRead;
919                         }
920
921                         if(nRead == nToRead)
922                                 nbyte-=nRead;
923                         else
924                                 nbyte = 0; /* no more to read */
925                                         
926                                         
927                         if(nbyte > 0){
928                                 yaffsfs_Unlock();
929                                 yaffsfs_Lock();
930                         }
931
932                 }
933
934                 yaffsfs_PutHandle(fd);
935
936                 if(!isPread) {
937                         if(totalRead >= 0)
938                                 h->position = startPos + totalRead;
939                         else {
940                                         /* todo error */
941                         }
942                 }
943
944         }
945
946         yaffsfs_Unlock();
947
948         return (totalRead >= 0) ? totalRead : -1;
949
950 }
951
952 int yaffs_read(int fd, void *buf, unsigned int nbyte)
953 {
954         return yaffsfs_do_read(fd, buf, nbyte, 0, 0);
955 }
956
957 int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
958 {
959         return yaffsfs_do_read(fd, buf, nbyte, 1, offset);
960 }
961
962 int yaffsfs_do_write(int fd, const void *vbuf, unsigned int nbyte, int isPwrite, int offset)
963 {
964         yaffsfs_Handle *h = NULL;
965         struct yaffs_obj *obj = NULL;
966         int pos = 0;
967         int startPos = 0;
968         int nWritten = 0;
969         int totalWritten = 0;
970         int write_trhrough = 0;
971         int nToWrite = 0;
972         const u8 *buf = (const u8 *)vbuf;
973
974         yaffsfs_Lock();
975         h = yaffsfs_GetHandlePointer(fd);
976         obj = yaffsfs_GetHandleObject(fd);
977
978         if(!h || !obj){
979                 /* bad handle */
980                 yaffsfs_SetError(-EBADF);
981                 totalWritten = -1;
982         } else if( h && obj && (!h->writing || obj->my_dev->read_only)){
983                 yaffsfs_SetError(-EINVAL);
984                 totalWritten=-1;
985         } else {
986                 if(h->append)
987                         startPos = yaffs_get_obj_length(obj);
988                 else if(isPwrite)
989                         startPos = offset;
990                 else
991                         startPos = h->position;
992
993                 yaffsfs_GetHandle(fd);
994                 pos = startPos;
995                 while(nbyte > 0) {
996
997                         nToWrite = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
998                         if(nToWrite > nbyte)
999                                 nToWrite = nbyte;
1000
1001                         /* Tricky bit... 
1002                          * Need to reverify object in case the device was
1003                          * remounted or unmounted in another thread.
1004                          */
1005                         obj = yaffsfs_GetHandleObject(fd);
1006                         if(!obj || obj->my_dev->read_only)
1007                                 nWritten = 0;
1008                         else
1009                                 nWritten = yaffs_wr_file(obj,buf,pos,nToWrite,
1010                                                         write_trhrough);
1011                         if(nWritten > 0){
1012                                 totalWritten += nWritten;
1013                                 pos += nWritten;
1014                                 buf += nWritten;
1015                         }
1016
1017                         if(nWritten == nToWrite)
1018                                 nbyte -= nToWrite;
1019                         else
1020                                 nbyte = 0;
1021
1022                         if(nWritten < 1 && totalWritten < 1){
1023                                 yaffsfs_SetError(-ENOSPC);
1024                                 totalWritten = -1;
1025                         }
1026
1027                         if(nbyte > 0){
1028                                 yaffsfs_Unlock();
1029                                 yaffsfs_Lock();
1030                         }
1031                 }
1032
1033                 yaffsfs_PutHandle(fd);
1034
1035                 if(!isPwrite){
1036                         if(totalWritten > 0)
1037                                 h->position = startPos + totalWritten;
1038                         else {
1039                                 /* todo error */
1040                         }
1041                 }
1042         }
1043
1044         yaffsfs_Unlock();
1045
1046         return (totalWritten >= 0) ? totalWritten : -1;
1047 }
1048
1049 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
1050 {
1051         return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
1052 }
1053
1054 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
1055 {
1056         return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
1057 }
1058
1059
1060 int yaffs_truncate(const YCHAR *path,off_t new_size)
1061 {
1062         struct yaffs_obj *obj = NULL;
1063         struct yaffs_obj *dir = NULL;
1064         int result = YAFFS_FAIL;
1065
1066         yaffsfs_Lock();
1067
1068         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1069
1070         if(!dir)
1071                 yaffsfs_SetError(-ENOTDIR);
1072         else if(!obj)
1073                 yaffsfs_SetError(-ENOENT);
1074         else if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
1075                 yaffsfs_SetError(-EISDIR);
1076         else if(obj->my_dev->read_only)
1077                 yaffsfs_SetError(-EACCES);
1078         else if(new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1079                 yaffsfs_SetError(-EINVAL);
1080         else
1081                 result = yaffs_resize_file(obj,new_size);
1082
1083         yaffsfs_Unlock();
1084
1085         return (result) ? 0 : -1;
1086 }
1087
1088 int yaffs_ftruncate(int fd, off_t new_size)
1089 {
1090         yaffsfs_Handle *h = NULL;
1091         struct yaffs_obj *obj = NULL;
1092         int result = 0;
1093
1094         yaffsfs_Lock();
1095         h = yaffsfs_GetHandlePointer(fd);
1096         obj = yaffsfs_GetHandleObject(fd);
1097
1098         if(!h || !obj)
1099                 /* bad handle */
1100                 yaffsfs_SetError(-EBADF);
1101         else if(obj->my_dev->read_only)
1102                 yaffsfs_SetError(-EACCES);
1103         else if( new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1104                 yaffsfs_SetError(-EINVAL);
1105         else
1106                 /* resize the file */
1107                 result = yaffs_resize_file(obj,new_size);
1108         yaffsfs_Unlock();
1109
1110         return (result) ? 0 : -1;
1111
1112 }
1113
1114 off_t yaffs_lseek(int fd, off_t offset, int whence)
1115 {
1116         yaffsfs_Handle *h = NULL;
1117         struct yaffs_obj *obj = NULL;
1118         int pos = -1;
1119         int fSize = -1;
1120
1121         yaffsfs_Lock();
1122         h = yaffsfs_GetHandlePointer(fd);
1123         obj = yaffsfs_GetHandleObject(fd);
1124
1125         if(!h || !obj){
1126                 /* bad handle */
1127                 yaffsfs_SetError(-EBADF);
1128         } else {
1129                 if(whence == SEEK_SET){
1130                         if(offset >= 0)
1131                                 pos = offset;
1132                 } else if(whence == SEEK_CUR) {
1133                         if( (h->position + offset) >= 0)
1134                                 pos = (h->position + offset);
1135                 } else if(whence == SEEK_END) {
1136                         fSize = yaffs_get_obj_length(obj);
1137                         if(fSize >= 0 && (fSize + offset) >= 0)
1138                                 pos = fSize + offset;
1139                 } 
1140
1141                 if(pos >= 0)
1142                         h->position = pos;
1143                 else
1144                         yaffsfs_SetError(-EINVAL);
1145         }
1146
1147         yaffsfs_Unlock();
1148
1149         return pos;
1150 }
1151
1152
1153 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
1154 {
1155         struct yaffs_obj *dir = NULL;
1156         struct yaffs_obj *obj = NULL;
1157         YCHAR *name;
1158         int result = YAFFS_FAIL;
1159
1160         yaffsfs_Lock();
1161
1162         obj = yaffsfs_FindObject(NULL,path,0,0,NULL);
1163         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
1164
1165         if(!dir)
1166                 yaffsfs_SetError(-ENOTDIR);
1167         else if(!obj)
1168                 yaffsfs_SetError(-ENOENT);
1169         else if(obj->my_dev->read_only)
1170                 yaffsfs_SetError(-EINVAL);
1171         else if(!isDirectory && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1172                 yaffsfs_SetError(-EISDIR);
1173         else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1174                 yaffsfs_SetError(-ENOTDIR);
1175         else {
1176                 result = yaffs_unlinker(dir,name);
1177
1178                 if(result == YAFFS_FAIL && isDirectory)
1179                         yaffsfs_SetError(-ENOTEMPTY);
1180         }
1181
1182         yaffsfs_Unlock();
1183
1184         /* todo error */
1185
1186         return (result == YAFFS_FAIL) ? -1 : 0;
1187 }
1188
1189
1190 int yaffs_unlink(const YCHAR *path)
1191 {
1192         return yaffsfs_DoUnlink(path,0);
1193 }
1194
1195 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1196 {
1197         struct yaffs_obj *olddir = NULL;
1198         struct yaffs_obj *newdir = NULL;
1199         struct yaffs_obj *obj = NULL;
1200         YCHAR *oldname;
1201         YCHAR *newname;
1202         int result= YAFFS_FAIL;
1203         int rename_allowed = 1;
1204
1205         yaffsfs_Lock();
1206
1207         olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1208         newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1209         obj = yaffsfs_FindObject(NULL,oldPath,0,0,NULL);
1210
1211         if(!olddir || !newdir) {
1212                 yaffsfs_SetError(-ENOTDIR);
1213                 rename_allowed = 0;
1214         } else if(!obj) {
1215                 yaffsfs_SetError(-ENOENT);
1216                 rename_allowed = 0;
1217         } else if(obj->my_dev->read_only){
1218                 yaffsfs_SetError(-EROFS);
1219                 rename_allowed = 0;
1220         } else if(olddir->my_dev != newdir->my_dev) {
1221                 /* Rename must be on same device */
1222                 yaffsfs_SetError(-EXDEV);
1223                 rename_allowed = 0;
1224         } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1225                 /*
1226                  * It is a directory, check that it is not being renamed to
1227                  * being its own decendent.
1228                  * Do this by tracing from the new directory back to the root, checking for obj
1229                  */
1230
1231                 struct yaffs_obj *xx = newdir;
1232
1233                 while( rename_allowed && xx){
1234                         if(xx == obj)
1235                                 rename_allowed = 0;
1236                         xx = xx->parent;
1237                 }
1238                 if(!rename_allowed)
1239                         yaffsfs_SetError(-EINVAL);
1240         }
1241
1242         if(rename_allowed)
1243                 result = yaffs_rename_obj(olddir,oldname,newdir,newname);
1244
1245         yaffsfs_Unlock();
1246
1247         return (result == YAFFS_FAIL) ? -1 : 0;
1248 }
1249
1250
1251 static int yaffsfs_DoStat(struct yaffs_obj *obj,struct yaffs_stat *buf)
1252 {
1253         int retVal = -1;
1254
1255         obj = yaffs_get_equivalent_obj(obj);
1256
1257         if(obj && buf){
1258                 buf->st_dev = (int)obj->my_dev->os_context;
1259                 buf->st_ino = obj->obj_id;
1260                 buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
1261
1262                 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1263                         buf->st_mode |= S_IFDIR;
1264                 else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1265                         buf->st_mode |= S_IFLNK;
1266                 else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1267                         buf->st_mode |= S_IFREG;
1268
1269                 buf->st_nlink = yaffs_get_obj_link_count(obj);
1270                 buf->st_uid = 0;
1271                 buf->st_gid = 0;;
1272                 buf->st_rdev = obj->yst_rdev;
1273                 buf->st_size = yaffs_get_obj_length(obj);
1274                 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
1275                 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1276 #if CONFIG_YAFFS_WINCE
1277                 buf->yst_wince_atime[0] = obj->win_atime[0];
1278                 buf->yst_wince_atime[1] = obj->win_atime[1];
1279                 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1280                 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1281                 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1282                 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1283 #else
1284                 buf->yst_atime = obj->yst_atime;
1285                 buf->yst_ctime = obj->yst_ctime;
1286                 buf->yst_mtime = obj->yst_mtime;
1287 #endif
1288                 retVal = 0;
1289         }
1290         return retVal;
1291 }
1292
1293 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1294 {
1295         struct yaffs_obj *obj=NULL;
1296         struct yaffs_obj *dir=NULL;
1297
1298         int retVal = -1;
1299
1300         yaffsfs_Lock();
1301
1302         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1303
1304         if(!doLStat && obj)
1305                 obj = yaffsfs_FollowLink(obj,0);
1306
1307         if(!dir)
1308                 yaffsfs_SetError(-ENOTDIR);
1309         else if(!obj)
1310                 yaffsfs_SetError(-ENOENT);
1311         else
1312                 retVal = yaffsfs_DoStat(obj,buf);
1313
1314         yaffsfs_Unlock();
1315
1316         return retVal;
1317
1318 }
1319
1320 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1321 {
1322         return yaffsfs_DoStatOrLStat(path,buf,0);
1323 }
1324
1325 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1326 {
1327         return yaffsfs_DoStatOrLStat(path,buf,1);
1328 }
1329
1330 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1331 {
1332         struct yaffs_obj *obj;
1333
1334         int retVal = -1;
1335
1336         yaffsfs_Lock();
1337         obj = yaffsfs_GetHandleObject(fd);
1338
1339         if(obj)
1340                 retVal = yaffsfs_DoStat(obj,buf);
1341         else
1342                 /* bad handle */
1343                 yaffsfs_SetError(-EBADF);
1344
1345         yaffsfs_Unlock();
1346
1347         return retVal;
1348 }
1349
1350 #ifndef CONFIG_YAFFS_WINCE
1351 /* xattrib functions */
1352
1353
1354 static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags, int follow)
1355 {
1356         struct yaffs_obj *obj;
1357         struct yaffs_obj *dir;
1358
1359         int retVal = -1;
1360
1361         yaffsfs_Lock();
1362
1363         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1364
1365         if(follow)
1366                 obj = yaffsfs_FollowLink(obj,0);
1367
1368         if(!dir) 
1369                 yaffsfs_SetError(-ENOTDIR);
1370         else if(!obj) 
1371                 yaffsfs_SetError(-ENOENT);
1372         else {
1373                 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1374                 if(retVal< 0){
1375                         yaffsfs_SetError(retVal);
1376                         retVal = -1;
1377                 }
1378         }
1379
1380         yaffsfs_Unlock();
1381
1382         return retVal;
1383
1384 }
1385
1386 int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1387 {
1388         return yaffs_do_setxattr(path, name, data, size, flags, 1);
1389 }
1390
1391 int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1392 {
1393         return yaffs_do_setxattr(path, name, data, size, flags, 0);
1394 }
1395
1396
1397
1398 int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
1399 {
1400         struct yaffs_obj *obj;
1401
1402         int retVal = -1;
1403
1404         yaffsfs_Lock();
1405         obj = yaffsfs_GetHandleObject(fd);
1406
1407         if(!obj) 
1408                 yaffsfs_SetError(-EBADF);
1409         else {
1410                 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1411                 if(retVal< 0){
1412                         yaffsfs_SetError(retVal);
1413                         retVal = -1;
1414                 }
1415         }
1416
1417         yaffsfs_Unlock();
1418
1419         return retVal;
1420 }
1421
1422 static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
1423 {
1424         struct yaffs_obj *obj;
1425         struct yaffs_obj *dir;
1426
1427         int retVal = -1;
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_get_xattrib(obj,name,data,size);
1442                 if(retVal< 0){
1443                         yaffsfs_SetError(retVal);
1444                         retVal = -1;
1445                 }
1446         }
1447         yaffsfs_Unlock();
1448
1449         return retVal;
1450
1451 }
1452
1453 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1454 {
1455         return yaffs_do_getxattr( path, name, data, size, 1);
1456 }
1457 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1458 {
1459         return yaffs_do_getxattr( path, name, data, size, 0);
1460 }
1461
1462
1463
1464 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1465 {
1466         struct yaffs_obj *obj;
1467
1468         int retVal = -1;
1469
1470         yaffsfs_Lock();
1471         obj = yaffsfs_GetHandleObject(fd);
1472
1473         if(obj) {
1474                 retVal = yaffs_get_xattrib(obj,name,data,size);
1475                 if(retVal< 0){
1476                         yaffsfs_SetError(retVal);
1477                         retVal = -1;
1478                 }
1479         } else
1480                 /* bad handle */
1481                 yaffsfs_SetError(-EBADF);
1482
1483         yaffsfs_Unlock();
1484
1485         return retVal;
1486 }
1487
1488 static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
1489 {
1490         struct yaffs_obj *obj=NULL;
1491         struct yaffs_obj *dir=NULL;
1492
1493         int retVal = -1;
1494
1495         yaffsfs_Lock();
1496
1497         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1498
1499         if(follow)
1500                 obj = yaffsfs_FollowLink(obj,0);
1501
1502         if(!dir) 
1503                 yaffsfs_SetError(-ENOTDIR);
1504         else if(!obj) 
1505                 yaffsfs_SetError(-ENOENT);
1506         else {
1507                 retVal = yaffs_list_xattrib(obj, data,size);
1508                 if(retVal< 0){
1509                         yaffsfs_SetError(retVal);
1510                         retVal = -1;
1511                 }
1512         }
1513
1514         yaffsfs_Unlock();
1515
1516         return retVal;
1517
1518 }
1519
1520 int yaffs_listxattr(const YCHAR *path, char *data, int size)
1521 {
1522         return yaffs_do_listxattr(path, data, size, 1);
1523 }
1524
1525 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
1526 {
1527         return yaffs_do_listxattr(path, data, size, 0);
1528 }
1529
1530 int yaffs_flistxattr(int fd, char *data, int size)
1531 {
1532         struct yaffs_obj *obj;
1533
1534         int retVal = -1;
1535
1536         yaffsfs_Lock();
1537         obj = yaffsfs_GetHandleObject(fd);
1538
1539         if(obj) {
1540                 retVal = yaffs_list_xattrib(obj,data,size);
1541                 if(retVal< 0){
1542                         yaffsfs_SetError(retVal);
1543                         retVal = -1;
1544                 }
1545         } else
1546                 /* bad handle */
1547                 yaffsfs_SetError(-EBADF);
1548
1549         yaffsfs_Unlock();
1550
1551         return retVal;
1552 }
1553
1554 static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
1555 {
1556         struct yaffs_obj *obj=NULL;
1557         struct yaffs_obj *dir=NULL;
1558
1559         int retVal = -1;
1560
1561         yaffsfs_Lock();
1562
1563         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1564
1565         if(follow)
1566                 obj = yaffsfs_FollowLink(obj,0);
1567
1568         if(!dir) 
1569                 yaffsfs_SetError(-ENOTDIR);
1570         else if(!obj) 
1571                 yaffsfs_SetError(-ENOENT);
1572         else {
1573                 retVal = yaffs_remove_xattrib(obj,name);
1574                 if(retVal< 0){
1575                         yaffsfs_SetError(retVal);
1576                         retVal = -1;
1577                 }
1578         }
1579
1580         yaffsfs_Unlock();
1581
1582         return retVal;
1583
1584 }
1585
1586 int yaffs_removexattr(const YCHAR *path, const char *name)
1587 {
1588         return yaffs_do_removexattr(path, name, 1);
1589 }
1590
1591 int yaffs_lremovexattr(const YCHAR *path, const char *name)
1592 {
1593         return yaffs_do_removexattr(path, name, 0);
1594 }
1595
1596 int yaffs_fremovexattr(int fd, const char *name)
1597 {
1598         struct yaffs_obj *obj;
1599
1600         int retVal = -1;
1601
1602         yaffsfs_Lock();
1603         obj = yaffsfs_GetHandleObject(fd);
1604
1605         if(obj){
1606                 retVal = yaffs_remove_xattrib(obj,name);
1607                 if(retVal< 0){
1608                         yaffsfs_SetError(retVal);
1609                         retVal = -1;
1610                 }
1611         }else
1612                 /* bad handle */
1613                 yaffsfs_SetError(-EBADF);
1614
1615         yaffsfs_Unlock();
1616
1617         return retVal;
1618 }
1619 #endif
1620
1621 #ifdef CONFIG_YAFFS_WINCE
1622 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1623 {
1624         struct yaffs_obj *obj;
1625
1626         int retVal = -1;
1627
1628         yaffsfs_Lock();
1629         obj = yaffsfs_GetHandleObject(fd);
1630
1631         if(obj){
1632
1633                 if(wctime){
1634                         wctime[0] = obj->win_ctime[0];
1635                         wctime[1] = obj->win_ctime[1];
1636                 }
1637                 if(watime){
1638                         watime[0] = obj->win_atime[0];
1639                         watime[1] = obj->win_atime[1];
1640                 }
1641                 if(wmtime){
1642                         wmtime[0] = obj->win_mtime[0];
1643                         wmtime[1] = obj->win_mtime[1];
1644                 }
1645
1646
1647                 retVal = 0;
1648         } else
1649                 /*  bad handle */
1650                 yaffsfs_SetError(-EBADF);               
1651         
1652         yaffsfs_Unlock();
1653         
1654         return retVal;
1655 }
1656
1657
1658 int yaffs_set_wince_times(int fd, 
1659                                                   const unsigned *wctime, 
1660                                                   const unsigned *watime, 
1661                                                   const unsigned *wmtime)
1662 {
1663         struct yaffs_obj *obj;
1664         int result;
1665         int retVal = -1;
1666
1667         yaffsfs_Lock();
1668         obj = yaffsfs_GetHandleObject(fd);
1669
1670         if(obj){
1671
1672                 if(wctime){
1673                         obj->win_ctime[0] = wctime[0];
1674                         obj->win_ctime[1] = wctime[1];
1675                 }
1676                 if(watime){
1677                         obj->win_atime[0] = watime[0];
1678                         obj->win_atime[1] = watime[1];
1679                 }
1680                 if(wmtime){
1681                         obj->win_mtime[0] = wmtime[0];
1682                         obj->win_mtime[1] = wmtime[1];
1683                 }
1684
1685                 obj->dirty = 1;
1686                 result = yaffs_flush_file(obj,0,0);
1687                 retVal = 0;
1688         } else
1689                 /* bad handle */
1690                 yaffsfs_SetError(-EBADF);
1691
1692         yaffsfs_Unlock();
1693
1694         return retVal;
1695 }
1696
1697 #endif
1698
1699
1700 static int yaffsfs_DoChMod(struct yaffs_obj *obj,mode_t mode)
1701 {
1702         int result = -1;
1703
1704         if(obj)
1705                 obj = yaffs_get_equivalent_obj(obj);
1706
1707         if(obj) {
1708                 obj->yst_mode = mode;
1709                 obj->dirty = 1;
1710                 result = yaffs_flush_file(obj,0,0);
1711         }
1712
1713         return result == YAFFS_OK ? 0 : -1;
1714 }
1715
1716
1717 int yaffs_access(const YCHAR *path, int amode)
1718 {
1719         struct yaffs_obj *obj=NULL;
1720         struct yaffs_obj *dir=NULL;
1721
1722         int retval = -1;
1723
1724         if(amode & ~(R_OK | W_OK | X_OK)){
1725                 yaffsfs_SetError(-EINVAL);
1726                 return -1;
1727         }
1728
1729         yaffsfs_Lock();
1730
1731         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1732
1733         if(!dir) 
1734                 yaffsfs_SetError(-ENOTDIR);
1735         else if(!obj) 
1736                 yaffsfs_SetError(-ENOENT);
1737         else {
1738                 int access_ok = 1;
1739
1740                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1741                         access_ok = 0;
1742                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1743                         access_ok = 0;
1744                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1745                         access_ok = 0;
1746
1747                 if(!access_ok)
1748                         yaffsfs_SetError(-EACCES);
1749                 else
1750                         retval = 0;
1751         }
1752
1753         yaffsfs_Unlock();
1754
1755         return retval;
1756
1757 }
1758
1759
1760 int yaffs_chmod(const YCHAR *path, mode_t mode)
1761 {
1762         struct yaffs_obj *obj=NULL;
1763         struct yaffs_obj *dir=NULL;
1764         int retVal = -1;
1765
1766         if(mode & ~(0777)){
1767                 yaffsfs_SetError(-EINVAL);
1768                 return -1;
1769         }
1770
1771         yaffsfs_Lock();
1772
1773         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1774
1775         if(!dir) 
1776                 yaffsfs_SetError(-ENOTDIR);
1777         else if(!obj) 
1778                 yaffsfs_SetError(-ENOENT);
1779         else if(obj->my_dev->read_only)
1780                 yaffsfs_SetError(-EROFS);
1781         else
1782                 retVal = yaffsfs_DoChMod(obj,mode);
1783
1784         yaffsfs_Unlock();
1785
1786         return retVal;
1787
1788 }
1789
1790
1791 int yaffs_fchmod(int fd, mode_t mode)
1792 {
1793         struct yaffs_obj *obj;
1794         int retVal = -1;
1795
1796         if(mode & ~(0777)){
1797                 yaffsfs_SetError(-EINVAL);
1798                 return -1;
1799         }
1800
1801         yaffsfs_Lock();
1802         obj = yaffsfs_GetHandleObject(fd);
1803
1804         if(!obj)
1805                 yaffsfs_SetError(-EBADF);
1806         else if(obj->my_dev->read_only)
1807                 yaffsfs_SetError(-EROFS);
1808         else
1809                 retVal = yaffsfs_DoChMod(obj,mode);
1810
1811         yaffsfs_Unlock();
1812
1813         return retVal;
1814 }
1815
1816
1817 static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path)
1818 {
1819         YCHAR *alt_path = NULL;
1820         int path_length;
1821         int i;
1822
1823         /*
1824          * We don't have a definition for max path length.
1825          * We will use 3 * max name length instead.
1826          */
1827         *ret_path = NULL;
1828         path_length = strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1);
1829
1830         /* If the last character is a path divider, then we need to
1831          * trim it back so that the name look-up works properly.
1832          * eg. /foo/new_dir/ -> /foo/newdir
1833          * Curveball: Need to handle multiple path dividers:
1834          * eg. /foof/sdfse///// -> /foo/sdfse
1835          */
1836         if(path_length > 0 && 
1837                 yaffsfs_IsPathDivider(path[path_length-1])){
1838                 alt_path = YMALLOC(path_length + 1);
1839                 if(!alt_path)
1840                         return -1;
1841                 strcpy(alt_path, path);
1842                 for(i = path_length-1;
1843                         i >= 0 && yaffsfs_IsPathDivider(alt_path[i]);
1844                         i--)
1845                         alt_path[i] = (YCHAR) 0;
1846         }
1847         *ret_path = alt_path;
1848         return 0;
1849 }
1850
1851 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1852 {
1853         struct yaffs_obj *parent = NULL;
1854         struct yaffs_obj *dir = NULL;
1855         YCHAR *name;
1856         YCHAR *alt_path = NULL;
1857         int retVal= -1;
1858
1859         if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
1860                 yaffsfs_SetError(-ENOMEM);
1861                 return -1;
1862         }
1863         if(alt_path)
1864                 path = alt_path;
1865         
1866         yaffsfs_Lock();
1867         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1868         if(!parent)
1869                 yaffsfs_SetError(-ENOTDIR);
1870         else if(parent && yaffs_strnlen(name,5) == 0){
1871                 /* Trying to make the root itself */
1872                 yaffsfs_SetError(-EEXIST);
1873         } else if(parent && parent->my_dev->read_only)
1874                 yaffsfs_SetError(-EROFS);
1875         else {
1876                 dir = yaffs_create_dir(parent,name,mode,0,0);
1877                 if(dir)
1878                         retVal = 0;
1879                 else if (yaffs_find_by_name(parent,name))
1880                         yaffsfs_SetError(-EEXIST); /* the name already exists */
1881                 else
1882                         yaffsfs_SetError(-ENOSPC); /* just assume no space */
1883         }
1884
1885         yaffsfs_Unlock();
1886
1887         if(alt_path)
1888                 YFREE(alt_path);
1889
1890         return retVal;
1891 }
1892
1893 int yaffs_rmdir(const YCHAR *path)
1894 {
1895         int result;
1896         YCHAR *alt_path;
1897
1898         if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
1899                 yaffsfs_SetError(-ENOMEM);
1900                 return -1;
1901         }
1902         if(alt_path)
1903                 path = alt_path;
1904         result =  yaffsfs_DoUnlink(path,1);
1905         if(alt_path)
1906                 YFREE(alt_path);
1907         return result;
1908 }
1909
1910
1911 void * yaffs_getdev(const YCHAR *path)
1912 {
1913         struct yaffs_dev *dev=NULL;
1914         YCHAR *dummy;
1915         dev = yaffsfs_FindDevice(path,&dummy);
1916         return (void *)dev;
1917 }
1918
1919 int yaffs_mount2(const YCHAR *path,int read_only)
1920 {
1921         int retVal=-1;
1922         int result=YAFFS_FAIL;
1923         struct yaffs_dev *dev=NULL;
1924
1925         T(YAFFS_TRACE_MOUNT,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1926
1927         yaffsfs_Lock();
1928
1929         yaffsfs_InitHandles();
1930
1931         dev = yaffsfs_FindMountPoint(path);
1932         if(dev){
1933                 if(!dev->is_mounted){
1934                         dev->read_only = read_only ? 1 : 0;
1935                         result = yaffs_guts_initialise(dev);
1936                         if(result == YAFFS_FAIL)
1937                                 /* todo error - mount failed */
1938                                 yaffsfs_SetError(-ENOMEM);
1939                         retVal = result ? 0 : -1;
1940
1941                 }
1942                 else
1943                         /* todo error - already mounted. */
1944                         yaffsfs_SetError(-EBUSY);
1945         } else
1946                 /* todo error - no device */
1947                 yaffsfs_SetError(-ENODEV);
1948
1949         yaffsfs_Unlock();
1950         return retVal;
1951
1952 }
1953
1954 int yaffs_mount(const YCHAR *path)
1955 {
1956         return yaffs_mount2(path,0);
1957 }
1958
1959 int yaffs_sync(const YCHAR *path)
1960 {
1961         int retVal=-1;
1962         struct yaffs_dev *dev=NULL;
1963         YCHAR *dummy;
1964         
1965         yaffsfs_Lock();
1966         dev = yaffsfs_FindDevice(path,&dummy);
1967         if(dev){
1968                 if(dev->is_mounted){
1969                         
1970                         yaffs_flush_whole_cache(dev);
1971                         yaffs_checkpoint_save(dev);
1972                         retVal = 0;
1973                         
1974                 } else
1975                         /* todo error - not mounted. */
1976                         yaffsfs_SetError(-EINVAL);
1977                         
1978         }else
1979                 /* todo error - no device */
1980                 yaffsfs_SetError(-ENODEV);
1981
1982         yaffsfs_Unlock();
1983         return retVal;  
1984 }
1985
1986
1987 int yaffs_remount(const YCHAR *path, int force, int read_only)
1988 {
1989         int retVal=-1;
1990         struct yaffs_dev *dev=NULL;
1991         yaffsfs_Handle *yh;
1992
1993         yaffsfs_Lock();
1994         dev = yaffsfs_FindMountPoint(path);
1995         if(dev){
1996                 if(dev->is_mounted){
1997                         int i;
1998                         int inUse;
1999
2000                         yaffs_flush_whole_cache(dev);
2001
2002                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
2003                                 yh = & yaffsfs_handle[i];
2004                                 if(yh->useCount>0 && 
2005                                         yaffsfs_inode[yh->inodeId].iObj->my_dev == dev)
2006                                         inUse = 1; /* the device is in use, can't unmount */
2007                         }
2008
2009                         if(!inUse || force){
2010                                 if(read_only)
2011                                         yaffs_checkpoint_save(dev);
2012                                 dev->read_only =  read_only ? 1 : 0;
2013                                 retVal = 0;
2014                         } else
2015                                 yaffsfs_SetError(-EBUSY);
2016
2017                 } else
2018                         yaffsfs_SetError(-EINVAL);
2019
2020         }
2021         else
2022                 yaffsfs_SetError(-ENODEV);
2023
2024         yaffsfs_Unlock();
2025         return retVal;
2026
2027 }
2028
2029 int yaffs_unmount2(const YCHAR *path, int force)
2030 {
2031         int retVal=-1;
2032         struct yaffs_dev *dev=NULL;
2033
2034         yaffsfs_Lock();
2035         dev = yaffsfs_FindMountPoint(path);
2036         if(dev){
2037                 if(dev->is_mounted){
2038                         int i;
2039                         int inUse;
2040
2041                         yaffs_flush_whole_cache(dev);
2042                         yaffs_checkpoint_save(dev);
2043
2044                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
2045                                 if(yaffsfs_handle[i].useCount > 0 && 
2046                                 yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->my_dev == dev)
2047                                         inUse = 1; /* the device is in use, can't unmount */
2048                         }
2049
2050                         if(!inUse || force){
2051                                 if(inUse)
2052                                         yaffsfs_PutDeviceHandles(dev);
2053                                 yaffs_deinitialise(dev);
2054
2055                                 retVal = 0;
2056                         } else
2057                                 /* todo error can't unmount as files are open */
2058                                 yaffsfs_SetError(-EBUSY);
2059
2060                 } else
2061                         /* todo error - not mounted. */
2062                         yaffsfs_SetError(-EINVAL);
2063
2064         } else
2065                 /* todo error - no device */
2066                 yaffsfs_SetError(-ENODEV);
2067
2068         yaffsfs_Unlock();
2069         return retVal;
2070
2071 }
2072
2073 int yaffs_unmount(const YCHAR *path)
2074 {
2075         return yaffs_unmount2(path,0);
2076 }
2077
2078 loff_t yaffs_freespace(const YCHAR *path)
2079 {
2080         loff_t retVal=-1;
2081         struct yaffs_dev *dev=NULL;
2082         YCHAR *dummy;
2083
2084         yaffsfs_Lock();
2085         dev = yaffsfs_FindDevice(path,&dummy);
2086         if(dev  && dev->is_mounted){
2087                 retVal = yaffs_get_n_free_chunks(dev);
2088                 retVal *= dev->data_bytes_per_chunk;
2089
2090         } else
2091                 yaffsfs_SetError(-EINVAL);
2092
2093         yaffsfs_Unlock();
2094         return retVal;
2095 }
2096
2097 loff_t yaffs_totalspace(const YCHAR *path)
2098 {
2099         loff_t retVal=-1;
2100         struct yaffs_dev *dev=NULL;
2101         YCHAR *dummy;
2102
2103         yaffsfs_Lock();
2104         dev = yaffsfs_FindDevice(path,&dummy);
2105         if(dev  && dev->is_mounted){
2106                 retVal = (dev->param.end_block - dev->param.start_block + 1) - dev->param.n_reserved_blocks;
2107                 retVal *= dev->param.chunks_per_block;
2108                 retVal *= dev->data_bytes_per_chunk;
2109
2110         } else
2111                 yaffsfs_SetError(-EINVAL);
2112
2113         yaffsfs_Unlock();
2114         return retVal;
2115 }
2116
2117 int yaffs_inodecount(const YCHAR *path)
2118 {
2119         loff_t retVal= -1;
2120         struct yaffs_dev *dev=NULL;
2121         YCHAR *dummy;
2122
2123         yaffsfs_Lock();
2124         dev = yaffsfs_FindDevice(path,&dummy);
2125         if(dev  && dev->is_mounted) {
2126            int n_obj = dev->n_obj;
2127            if(n_obj > dev->n_hardlinks)
2128                 retVal = n_obj - dev->n_hardlinks;
2129         }
2130         
2131         if(retVal < 0)
2132                 yaffsfs_SetError(-EINVAL);
2133         
2134         yaffsfs_Unlock();
2135         return retVal;  
2136 }
2137
2138
2139 void yaffs_add_device(struct yaffs_dev *dev)
2140 {
2141         dev->is_mounted = 0;
2142         dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
2143
2144         if(!dev->dev_list.next)
2145                 INIT_LIST_HEAD(&dev->dev_list);
2146
2147         list_add(&dev->dev_list,&yaffsfs_deviceList);
2148 }
2149
2150 void yaffs_remove_device(struct yaffs_dev *dev)
2151 {
2152         list_del_init(&dev->dev_list);
2153 }
2154
2155
2156
2157
2158 /* Directory search stuff. */
2159
2160 /*
2161  * Directory search context
2162  *
2163  * NB this is an opaque structure.
2164  */
2165
2166
2167 typedef struct
2168 {
2169         u32 magic;
2170         yaffs_dirent de;                /* directory entry being used by this dsc */
2171         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
2172         struct yaffs_obj *dirObj;           /* ptr to directory being searched */
2173         struct yaffs_obj *nextReturn;       /* obj to be returned by next readddir */
2174         int offset;
2175         struct list_head others;       
2176 } yaffsfs_DirectorySearchContext;
2177
2178
2179
2180 static struct list_head search_contexts;
2181
2182
2183 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
2184 {
2185         if(dsc &&
2186            dsc->dirObj &&
2187            dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2188
2189            dsc->offset = 0;
2190
2191            if( list_empty(&dsc->dirObj->variant.dir_variant.children))
2192                 dsc->nextReturn = NULL;
2193            else
2194                 dsc->nextReturn = list_entry(dsc->dirObj->variant.dir_variant.children.next,
2195                                                 struct yaffs_obj,siblings);
2196         } else {
2197                 /* Hey someone isn't playing nice! */
2198         }
2199 }
2200
2201 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
2202 {
2203         if(dsc &&
2204            dsc->dirObj &&
2205            dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2206
2207            if( dsc->nextReturn == NULL ||
2208                list_empty(&dsc->dirObj->variant.dir_variant.children))
2209                 dsc->nextReturn = NULL;
2210            else {
2211                    struct list_head *next = dsc->nextReturn->siblings.next;
2212
2213                    if( next == &dsc->dirObj->variant.dir_variant.children)
2214                         dsc->nextReturn = NULL; /* end of list */
2215                    else
2216                         dsc->nextReturn = list_entry(next,struct yaffs_obj,siblings);
2217            }
2218         } else {
2219                 /* Hey someone isn't playing nice! */
2220         }
2221 }
2222
2223 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
2224 {
2225
2226         struct list_head *i;
2227         yaffsfs_DirectorySearchContext *dsc;
2228
2229         /* if search contexts not initilised then skip */
2230         if(!search_contexts.next)
2231                 return;
2232
2233         /* Iterate through the directory search contexts.
2234          * If any are the one being removed, then advance the dsc to
2235          * the next one to prevent a hanging ptr.
2236          */
2237          list_for_each(i, &search_contexts) {
2238                 if (i) {
2239                         dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
2240                         if(dsc->nextReturn == obj)
2241                                 yaffsfs_DirAdvance(dsc);
2242                 }
2243         }
2244
2245 }
2246
2247 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
2248 {
2249         yaffs_DIR *dir = NULL;
2250         struct yaffs_obj *obj = NULL;
2251         yaffsfs_DirectorySearchContext *dsc = NULL;
2252
2253         yaffsfs_Lock();
2254
2255         obj = yaffsfs_FindObject(NULL,dirname,0,1,NULL);
2256
2257         if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2258
2259                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
2260                 dir = (yaffs_DIR *)dsc;
2261
2262                 if(dsc){
2263                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
2264                         dsc->magic = YAFFS_MAGIC;
2265                         dsc->dirObj = obj;
2266                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
2267                         INIT_LIST_HEAD(&dsc->others);
2268
2269                         if(!search_contexts.next)
2270                                 INIT_LIST_HEAD(&search_contexts);
2271
2272                         list_add(&dsc->others,&search_contexts);       
2273                         yaffsfs_SetDirRewound(dsc);
2274                 }
2275
2276         }
2277
2278         yaffsfs_Unlock();
2279
2280         return dir;
2281 }
2282
2283 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2284 {
2285         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2286         struct yaffs_dirent *retVal = NULL;
2287
2288         yaffsfs_Lock();
2289
2290         if(dsc && dsc->magic == YAFFS_MAGIC){
2291                 yaffsfs_SetError(0);
2292                 if(dsc->nextReturn){
2293                         dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
2294                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2295                         dsc->de.d_off = dsc->offset++;
2296                         yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2297                         if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2298                         {
2299                                 /* this should not happen! */
2300                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2301                         }
2302                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2303                         retVal = &dsc->de;
2304                         yaffsfs_DirAdvance(dsc);
2305                 } else
2306                         retVal = NULL;
2307         } else
2308                 yaffsfs_SetError(-EBADF);
2309
2310         yaffsfs_Unlock();
2311
2312         return retVal;
2313
2314 }
2315
2316
2317 void yaffs_rewinddir(yaffs_DIR *dirp)
2318 {
2319         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2320
2321         yaffsfs_Lock();
2322
2323         yaffsfs_SetDirRewound(dsc);
2324
2325         yaffsfs_Unlock();
2326 }
2327
2328
2329 int yaffs_closedir(yaffs_DIR *dirp)
2330 {
2331         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2332
2333         yaffsfs_Lock();
2334         dsc->magic = 0;
2335         list_del(&dsc->others); /* unhook from list */
2336         YFREE(dsc);
2337         yaffsfs_Unlock();
2338         return 0;
2339 }
2340
2341 /* End of directory stuff */
2342
2343
2344 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2345 {
2346         struct yaffs_obj *parent = NULL;
2347         struct yaffs_obj *obj;
2348         YCHAR *name;
2349         int retVal= -1;
2350         int mode = 0; /* ignore for now */
2351
2352         yaffsfs_Lock();
2353         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
2354         if(!parent)
2355                 yaffsfs_SetError(-ENOTDIR);
2356         else if( strlen(name) < 1)
2357                 yaffsfs_SetError(-ENOENT);
2358         else if(parent->my_dev->read_only)
2359                 yaffsfs_SetError(-EROFS);
2360         else if(parent){
2361                 obj = yaffs_create_symlink(parent,name,mode,0,0,oldpath);
2362                 if(obj)
2363                         retVal = 0;
2364                 else{
2365                         yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
2366                         retVal = -1;
2367                 }
2368         }
2369
2370         yaffsfs_Unlock();
2371
2372         return retVal;
2373
2374 }
2375
2376 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
2377 {
2378         struct yaffs_obj *obj = NULL;
2379         struct yaffs_obj *dir = NULL;
2380         int retVal= -1;
2381
2382         yaffsfs_Lock();
2383
2384         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
2385
2386         if(!dir) 
2387                 yaffsfs_SetError(-ENOTDIR);
2388         else if(!obj) 
2389                 yaffsfs_SetError(-ENOENT);
2390         else if(obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
2391                 yaffsfs_SetError(-EINVAL);
2392         else {
2393                 YCHAR *alias = obj->variant.symlink_variant.alias;
2394                 memset(buf,0,bufsiz);
2395                 yaffs_strncpy(buf,alias,bufsiz - 1);
2396                 retVal = 0;
2397         }
2398         yaffsfs_Unlock();
2399         return retVal;
2400 }
2401
2402 int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
2403 {
2404         /* Creates a link called newpath to existing oldpath */
2405         struct yaffs_obj *obj = NULL;
2406         struct yaffs_obj *lnk = NULL;
2407         int retVal = -1;
2408
2409         yaffsfs_Lock();
2410
2411         obj = yaffsfs_FindObject(NULL,oldpath,0,1,NULL);
2412         lnk = yaffsfs_FindObject(NULL,linkpath,0,0,NULL);
2413
2414         if(!obj)
2415                 yaffsfs_SetError(-ENOENT);
2416         else if(obj->my_dev->read_only)
2417                 yaffsfs_SetError(-EINVAL);
2418         else if(lnk)
2419                 yaffsfs_SetError(-EEXIST);
2420         else {
2421                 struct yaffs_obj *newdir = NULL;
2422                 struct yaffs_obj *link = NULL;
2423
2424                 YCHAR *newname;
2425
2426                 newdir = yaffsfs_FindDirectory(NULL,linkpath,&newname,0);
2427
2428                 if(!newdir)
2429                         yaffsfs_SetError(-ENOTDIR);
2430                 else if(newdir->my_dev != obj->my_dev)
2431                         yaffsfs_SetError(-EXDEV);
2432                 
2433                 retVal = yaffsfs_CheckNameLength(newname);
2434                 
2435                 if(retVal == 0) {
2436                         link = yaffs_link_obj(newdir,newname,obj);
2437                         if(link)
2438                                 retVal = 0;
2439                         else{
2440                                 yaffsfs_SetError(-ENOSPC);
2441                                 retVal = -1;
2442                         }
2443
2444                 }
2445         }
2446         yaffsfs_Unlock();
2447
2448         return retVal;
2449 }
2450
2451 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
2452 {
2453         pathname=pathname;
2454         mode=mode;
2455         dev=dev;
2456         return -1;
2457 }
2458
2459
2460
2461 /*
2462  * yaffs_n_handles()
2463  * Returns number of handles attached to the object
2464  */
2465 int yaffs_n_handles(const YCHAR *path)
2466 {
2467         struct yaffs_obj *obj;
2468
2469         obj = yaffsfs_FindObject(NULL,path,0,1,NULL);
2470
2471         return yaffsfs_CountHandles(obj);
2472 }
2473
2474 int yaffs_get_error(void)
2475 {
2476         return yaffsfs_GetLastError();
2477 }
2478
2479 int yaffs_set_error(int error)
2480 {
2481         /*yaffsfs_SetError does not return. So the program is assumed to have worked. */
2482         yaffsfs_SetError(error);
2483         return 0;
2484 }
2485
2486 int yaffs_dump_dev(const YCHAR *path)
2487 {
2488 #if 1
2489         path=path;
2490 #else
2491         YCHAR *rest;
2492
2493         struct yaffs_obj *obj = yaffsfs_FindRoot(path,&rest);
2494
2495         if(obj){
2496                 struct yaffs_dev *dev = obj->my_dev;
2497
2498                 printf("\n"
2499                            "n_page_writes.......... %d\n"
2500                            "n_page_reads........... %d\n"
2501                            "n_erasures....... %d\n"
2502                            "n_gc_copies............ %d\n"
2503                            "garbageCollections... %d\n"
2504                            "passiveGarbageColl'ns %d\n"
2505                            "\n",
2506                                 dev->n_page_writes,
2507                                 dev->n_page_reads,
2508                                 dev->n_erasures,
2509                                 dev->n_gc_copies,
2510                                 dev->garbageCollections,
2511                                 dev->passiveGarbageCollections
2512                 );
2513
2514         }
2515
2516 #endif
2517         return 0;
2518 }
2519