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