Merge branch 'master' of ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2
[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_rmdir(const YCHAR *path)
1191 {
1192         return yaffsfs_DoUnlink(path,1);
1193 }
1194
1195 int yaffs_unlink(const YCHAR *path)
1196 {
1197         return yaffsfs_DoUnlink(path,0);
1198 }
1199
1200 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1201 {
1202         struct yaffs_obj *olddir = NULL;
1203         struct yaffs_obj *newdir = NULL;
1204         struct yaffs_obj *obj = NULL;
1205         YCHAR *oldname;
1206         YCHAR *newname;
1207         int result= YAFFS_FAIL;
1208         int rename_allowed = 1;
1209
1210         yaffsfs_Lock();
1211
1212         olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1213         newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1214         obj = yaffsfs_FindObject(NULL,oldPath,0,0,NULL);
1215
1216         if(!olddir || !newdir) {
1217                 yaffsfs_SetError(-ENOTDIR);
1218                 rename_allowed = 0;
1219         } else if(!obj) {
1220                 yaffsfs_SetError(-ENOENT);
1221                 rename_allowed = 0;
1222         } else if(obj->my_dev->read_only){
1223                 yaffsfs_SetError(-EROFS);
1224                 rename_allowed = 0;
1225         } else if(olddir->my_dev != newdir->my_dev) {
1226                 /* Rename must be on same device */
1227                 yaffsfs_SetError(-EXDEV);
1228                 rename_allowed = 0;
1229         } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1230                 /*
1231                  * It is a directory, check that it is not being renamed to
1232                  * being its own decendent.
1233                  * Do this by tracing from the new directory back to the root, checking for obj
1234                  */
1235
1236                 struct yaffs_obj *xx = newdir;
1237
1238                 while( rename_allowed && xx){
1239                         if(xx == obj)
1240                                 rename_allowed = 0;
1241                         xx = xx->parent;
1242                 }
1243                 if(!rename_allowed)
1244                         yaffsfs_SetError(-EINVAL);
1245         }
1246
1247         if(rename_allowed)
1248                 result = yaffs_rename_obj(olddir,oldname,newdir,newname);
1249
1250         yaffsfs_Unlock();
1251
1252         return (result == YAFFS_FAIL) ? -1 : 0;
1253 }
1254
1255
1256 static int yaffsfs_DoStat(struct yaffs_obj *obj,struct yaffs_stat *buf)
1257 {
1258         int retVal = -1;
1259
1260         obj = yaffs_get_equivalent_obj(obj);
1261
1262         if(obj && buf){
1263                 buf->st_dev = (int)obj->my_dev->os_context;
1264                 buf->st_ino = obj->obj_id;
1265                 buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
1266
1267                 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1268                         buf->st_mode |= S_IFDIR;
1269                 else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1270                         buf->st_mode |= S_IFLNK;
1271                 else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1272                         buf->st_mode |= S_IFREG;
1273
1274                 buf->st_nlink = yaffs_get_obj_link_count(obj);
1275                 buf->st_uid = 0;
1276                 buf->st_gid = 0;;
1277                 buf->st_rdev = obj->yst_rdev;
1278                 buf->st_size = yaffs_get_obj_length(obj);
1279                 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
1280                 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1281 #if CONFIG_YAFFS_WINCE
1282                 buf->yst_wince_atime[0] = obj->win_atime[0];
1283                 buf->yst_wince_atime[1] = obj->win_atime[1];
1284                 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1285                 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1286                 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1287                 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1288 #else
1289                 buf->yst_atime = obj->yst_atime;
1290                 buf->yst_ctime = obj->yst_ctime;
1291                 buf->yst_mtime = obj->yst_mtime;
1292 #endif
1293                 retVal = 0;
1294         }
1295         return retVal;
1296 }
1297
1298 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1299 {
1300         struct yaffs_obj *obj=NULL;
1301         struct yaffs_obj *dir=NULL;
1302
1303         int retVal = -1;
1304
1305         yaffsfs_Lock();
1306
1307         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1308
1309         if(!doLStat && obj)
1310                 obj = yaffsfs_FollowLink(obj,0);
1311
1312         if(!dir)
1313                 yaffsfs_SetError(-ENOTDIR);
1314         else if(!obj)
1315                 yaffsfs_SetError(-ENOENT);
1316         else
1317                 retVal = yaffsfs_DoStat(obj,buf);
1318
1319         yaffsfs_Unlock();
1320
1321         return retVal;
1322
1323 }
1324
1325 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1326 {
1327         return yaffsfs_DoStatOrLStat(path,buf,0);
1328 }
1329
1330 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1331 {
1332         return yaffsfs_DoStatOrLStat(path,buf,1);
1333 }
1334
1335 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1336 {
1337         struct yaffs_obj *obj;
1338
1339         int retVal = -1;
1340
1341         yaffsfs_Lock();
1342         obj = yaffsfs_GetHandleObject(fd);
1343
1344         if(obj)
1345                 retVal = yaffsfs_DoStat(obj,buf);
1346         else
1347                 /* bad handle */
1348                 yaffsfs_SetError(-EBADF);
1349
1350         yaffsfs_Unlock();
1351
1352         return retVal;
1353 }
1354
1355 #ifndef CONFIG_YAFFS_WINCE
1356 /* xattrib functions */
1357
1358
1359 static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags, int follow)
1360 {
1361         struct yaffs_obj *obj;
1362         struct yaffs_obj *dir;
1363
1364         int retVal = -1;
1365
1366         yaffsfs_Lock();
1367
1368         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1369
1370         if(follow)
1371                 obj = yaffsfs_FollowLink(obj,0);
1372
1373         if(!dir) 
1374                 yaffsfs_SetError(-ENOTDIR);
1375         else if(!obj) 
1376                 yaffsfs_SetError(-ENOENT);
1377         else {
1378                 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1379                 if(retVal< 0){
1380                         yaffsfs_SetError(retVal);
1381                         retVal = -1;
1382                 }
1383         }
1384
1385         yaffsfs_Unlock();
1386
1387         return retVal;
1388
1389 }
1390
1391 int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1392 {
1393         return yaffs_do_setxattr(path, name, data, size, flags, 1);
1394 }
1395
1396 int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1397 {
1398         return yaffs_do_setxattr(path, name, data, size, flags, 0);
1399 }
1400
1401
1402
1403 int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
1404 {
1405         struct yaffs_obj *obj;
1406
1407         int retVal = -1;
1408
1409         yaffsfs_Lock();
1410         obj = yaffsfs_GetHandleObject(fd);
1411
1412         if(!obj) 
1413                 yaffsfs_SetError(-EBADF);
1414         else {
1415                 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1416                 if(retVal< 0){
1417                         yaffsfs_SetError(retVal);
1418                         retVal = -1;
1419                 }
1420         }
1421
1422         yaffsfs_Unlock();
1423
1424         return retVal;
1425 }
1426
1427 static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
1428 {
1429         struct yaffs_obj *obj;
1430         struct yaffs_obj *dir;
1431
1432         int retVal = -1;
1433
1434         yaffsfs_Lock();
1435
1436         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1437
1438         if(follow)
1439                 obj = yaffsfs_FollowLink(obj,0);
1440
1441         if(!dir) 
1442                 yaffsfs_SetError(-ENOTDIR);
1443         else if(!obj) 
1444                 yaffsfs_SetError(-ENOENT);
1445         else {
1446                 retVal = yaffs_get_xattrib(obj,name,data,size);
1447                 if(retVal< 0){
1448                         yaffsfs_SetError(retVal);
1449                         retVal = -1;
1450                 }
1451         }
1452         yaffsfs_Unlock();
1453
1454         return retVal;
1455
1456 }
1457
1458 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1459 {
1460         return yaffs_do_getxattr( path, name, data, size, 1);
1461 }
1462 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1463 {
1464         return yaffs_do_getxattr( path, name, data, size, 0);
1465 }
1466
1467
1468
1469 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1470 {
1471         struct yaffs_obj *obj;
1472
1473         int retVal = -1;
1474
1475         yaffsfs_Lock();
1476         obj = yaffsfs_GetHandleObject(fd);
1477
1478         if(obj) {
1479                 retVal = yaffs_get_xattrib(obj,name,data,size);
1480                 if(retVal< 0){
1481                         yaffsfs_SetError(retVal);
1482                         retVal = -1;
1483                 }
1484         } else
1485                 /* bad handle */
1486                 yaffsfs_SetError(-EBADF);
1487
1488         yaffsfs_Unlock();
1489
1490         return retVal;
1491 }
1492
1493 static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
1494 {
1495         struct yaffs_obj *obj=NULL;
1496         struct yaffs_obj *dir=NULL;
1497
1498         int retVal = -1;
1499
1500         yaffsfs_Lock();
1501
1502         obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
1503
1504         if(follow)
1505                 obj = yaffsfs_FollowLink(obj,0);
1506
1507         if(!dir) 
1508                 yaffsfs_SetError(-ENOTDIR);
1509         else if(!obj) 
1510                 yaffsfs_SetError(-ENOENT);
1511         else {
1512                 retVal = yaffs_list_xattrib(obj, data,size);
1513                 if(retVal< 0){
1514                         yaffsfs_SetError(retVal);
1515                         retVal = -1;
1516                 }
1517         }
1518
1519         yaffsfs_Unlock();
1520
1521         return retVal;
1522
1523 }
1524
1525 int yaffs_listxattr(const YCHAR *path, char *data, int size)
1526 {
1527         return yaffs_do_listxattr(path, data, size, 1);
1528 }
1529
1530 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
1531 {
1532         return yaffs_do_listxattr(path, data, size, 0);
1533 }
1534
1535 int yaffs_flistxattr(int fd, char *data, int size)
1536 {
1537         struct yaffs_obj *obj;
1538
1539         int retVal = -1;
1540
1541         yaffsfs_Lock();
1542         obj = yaffsfs_GetHandleObject(fd);
1543
1544         if(obj) {
1545                 retVal = yaffs_list_xattrib(obj,data,size);
1546                 if(retVal< 0){
1547                         yaffsfs_SetError(retVal);
1548                         retVal = -1;
1549                 }
1550         } else
1551                 /* bad handle */
1552                 yaffsfs_SetError(-EBADF);
1553
1554         yaffsfs_Unlock();
1555
1556         return retVal;
1557 }
1558
1559 static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
1560 {
1561         struct yaffs_obj *obj=NULL;
1562         struct yaffs_obj *dir=NULL;
1563
1564         int retVal = -1;
1565
1566         yaffsfs_Lock();
1567
1568         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1569
1570         if(follow)
1571                 obj = yaffsfs_FollowLink(obj,0);
1572
1573         if(!dir) 
1574                 yaffsfs_SetError(-ENOTDIR);
1575         else if(!obj) 
1576                 yaffsfs_SetError(-ENOENT);
1577         else {
1578                 retVal = yaffs_remove_xattrib(obj,name);
1579                 if(retVal< 0){
1580                         yaffsfs_SetError(retVal);
1581                         retVal = -1;
1582                 }
1583         }
1584
1585         yaffsfs_Unlock();
1586
1587         return retVal;
1588
1589 }
1590
1591 int yaffs_removexattr(const YCHAR *path, const char *name)
1592 {
1593         return yaffs_do_removexattr(path, name, 1);
1594 }
1595
1596 int yaffs_lremovexattr(const YCHAR *path, const char *name)
1597 {
1598         return yaffs_do_removexattr(path, name, 0);
1599 }
1600
1601 int yaffs_fremovexattr(int fd, const char *name)
1602 {
1603         struct yaffs_obj *obj;
1604
1605         int retVal = -1;
1606
1607         yaffsfs_Lock();
1608         obj = yaffsfs_GetHandleObject(fd);
1609
1610         if(obj){
1611                 retVal = yaffs_remove_xattrib(obj,name);
1612                 if(retVal< 0){
1613                         yaffsfs_SetError(retVal);
1614                         retVal = -1;
1615                 }
1616         }else
1617                 /* bad handle */
1618                 yaffsfs_SetError(-EBADF);
1619
1620         yaffsfs_Unlock();
1621
1622         return retVal;
1623 }
1624 #endif
1625
1626 #ifdef CONFIG_YAFFS_WINCE
1627 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1628 {
1629         struct yaffs_obj *obj;
1630
1631         int retVal = -1;
1632
1633         yaffsfs_Lock();
1634         obj = yaffsfs_GetHandleObject(fd);
1635
1636         if(obj){
1637
1638                 if(wctime){
1639                         wctime[0] = obj->win_ctime[0];
1640                         wctime[1] = obj->win_ctime[1];
1641                 }
1642                 if(watime){
1643                         watime[0] = obj->win_atime[0];
1644                         watime[1] = obj->win_atime[1];
1645                 }
1646                 if(wmtime){
1647                         wmtime[0] = obj->win_mtime[0];
1648                         wmtime[1] = obj->win_mtime[1];
1649                 }
1650
1651
1652                 retVal = 0;
1653         } else
1654                 /*  bad handle */
1655                 yaffsfs_SetError(-EBADF);               
1656         
1657         yaffsfs_Unlock();
1658         
1659         return retVal;
1660 }
1661
1662
1663 int yaffs_set_wince_times(int fd, 
1664                                                   const unsigned *wctime, 
1665                                                   const unsigned *watime, 
1666                                                   const unsigned *wmtime)
1667 {
1668         struct yaffs_obj *obj;
1669         int result;
1670         int retVal = -1;
1671
1672         yaffsfs_Lock();
1673         obj = yaffsfs_GetHandleObject(fd);
1674
1675         if(obj){
1676
1677                 if(wctime){
1678                         obj->win_ctime[0] = wctime[0];
1679                         obj->win_ctime[1] = wctime[1];
1680                 }
1681                 if(watime){
1682                         obj->win_atime[0] = watime[0];
1683                         obj->win_atime[1] = watime[1];
1684                 }
1685                 if(wmtime){
1686                         obj->win_mtime[0] = wmtime[0];
1687                         obj->win_mtime[1] = wmtime[1];
1688                 }
1689
1690                 obj->dirty = 1;
1691                 result = yaffs_flush_file(obj,0,0);
1692                 retVal = 0;
1693         } else
1694                 /* bad handle */
1695                 yaffsfs_SetError(-EBADF);
1696
1697         yaffsfs_Unlock();
1698
1699         return retVal;
1700 }
1701
1702 #endif
1703
1704
1705 static int yaffsfs_DoChMod(struct yaffs_obj *obj,mode_t mode)
1706 {
1707         int result = -1;
1708
1709         if(obj)
1710                 obj = yaffs_get_equivalent_obj(obj);
1711
1712         if(obj) {
1713                 obj->yst_mode = mode;
1714                 obj->dirty = 1;
1715                 result = yaffs_flush_file(obj,0,0);
1716         }
1717
1718         return result == YAFFS_OK ? 0 : -1;
1719 }
1720
1721
1722 int yaffs_access(const YCHAR *path, int amode)
1723 {
1724         struct yaffs_obj *obj=NULL;
1725         struct yaffs_obj *dir=NULL;
1726
1727         int retval = -1;
1728
1729         if(amode & ~(R_OK | W_OK | X_OK)){
1730                 yaffsfs_SetError(-EINVAL);
1731                 return -1;
1732         }
1733
1734         yaffsfs_Lock();
1735
1736         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1737
1738         if(!dir) 
1739                 yaffsfs_SetError(-ENOTDIR);
1740         else if(!obj) 
1741                 yaffsfs_SetError(-ENOENT);
1742         else {
1743                 int access_ok = 1;
1744
1745                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1746                         access_ok = 0;
1747                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1748                         access_ok = 0;
1749                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1750                         access_ok = 0;
1751
1752                 if(!access_ok)
1753                         yaffsfs_SetError(-EACCES);
1754                 else
1755                         retval = 0;
1756         }
1757
1758         yaffsfs_Unlock();
1759
1760         return retval;
1761
1762 }
1763
1764
1765 int yaffs_chmod(const YCHAR *path, mode_t mode)
1766 {
1767         struct yaffs_obj *obj=NULL;
1768         struct yaffs_obj *dir=NULL;
1769         int retVal = -1;
1770
1771         if(mode & ~(0777)){
1772                 yaffsfs_SetError(-EINVAL);
1773                 return -1;
1774         }
1775
1776         yaffsfs_Lock();
1777
1778         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
1779
1780         if(!dir) 
1781                 yaffsfs_SetError(-ENOTDIR);
1782         else if(!obj) 
1783                 yaffsfs_SetError(-ENOENT);
1784         else if(obj->my_dev->read_only)
1785                 yaffsfs_SetError(-EROFS);
1786         else
1787                 retVal = yaffsfs_DoChMod(obj,mode);
1788
1789         yaffsfs_Unlock();
1790
1791         return retVal;
1792
1793 }
1794
1795
1796 int yaffs_fchmod(int fd, mode_t mode)
1797 {
1798         struct yaffs_obj *obj;
1799         int retVal = -1;
1800
1801         if(mode & ~(0777)){
1802                 yaffsfs_SetError(-EINVAL);
1803                 return -1;
1804         }
1805
1806         yaffsfs_Lock();
1807         obj = yaffsfs_GetHandleObject(fd);
1808
1809         if(!obj)
1810                 yaffsfs_SetError(-EBADF);
1811         else if(obj->my_dev->read_only)
1812                 yaffsfs_SetError(-EROFS);
1813         else
1814                 retVal = yaffsfs_DoChMod(obj,mode);
1815
1816         yaffsfs_Unlock();
1817
1818         return retVal;
1819 }
1820
1821
1822 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1823 {
1824         struct yaffs_obj *parent = NULL;
1825         struct yaffs_obj *dir = NULL;
1826         YCHAR *name;
1827         YCHAR *use_path = NULL;
1828         int path_length = 0;
1829         int retVal= -1;
1830         int i;
1831
1832
1833         /*
1834          * We don't have a definition for max path length.
1835          * We will use 3 * max name length instead.
1836          */
1837         
1838         path_length = strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1);
1839
1840         /* If the last character is a path divider, then we need to
1841          * trim it back so that the name look-up works properly.
1842          * eg. /foo/new_dir/ -> /foo/newdir
1843          * Curveball: Need to handle multiple path dividers:
1844          * eg. /foof/sdfse///// -> /foo/sdfse
1845          */
1846         if(path_length > 0 && 
1847                 yaffsfs_IsPathDivider(path[path_length-1])){
1848                 use_path = YMALLOC(path_length + 1);
1849                 if(!use_path){
1850                         yaffsfs_SetError(-ENOMEM);
1851                         return -1;
1852                 }
1853                 strcpy(use_path, path);
1854                 for(i = path_length-1;
1855                         i >= 0 && yaffsfs_IsPathDivider(use_path[i]);
1856                         i--)
1857                         use_path[i] = (YCHAR) 0;
1858                 path = use_path;
1859         }
1860         
1861         yaffsfs_Lock();
1862         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1863         if(parent && yaffs_strnlen(name,5) == 0){
1864                 /* Trying to make the root itself */
1865                 yaffsfs_SetError(-EEXIST);
1866         } else if(parent && parent->my_dev->read_only){
1867                 yaffsfs_SetError(-EINVAL);
1868         } else {
1869                 if(parent)
1870                         dir = yaffs_create_dir(parent,name,mode,0,0);
1871                 if(dir)
1872                         retVal = 0;
1873                 else {
1874                         if(!parent)
1875                                 yaffsfs_SetError(-ENOENT); /* missing path */
1876                         else if (yaffs_find_by_name(parent,name))
1877                                 yaffsfs_SetError(-EEXIST); /* the name already exists */
1878                         else
1879                                 yaffsfs_SetError(-ENOSPC); /* just assume no space */
1880                         retVal = -1;
1881                 }
1882         }
1883
1884         yaffsfs_Unlock();
1885
1886         if(use_path)
1887                 YFREE(use_path);
1888
1889         return retVal;
1890 }
1891
1892 void * yaffs_getdev(const YCHAR *path)
1893 {
1894         struct yaffs_dev *dev=NULL;
1895         YCHAR *dummy;
1896         dev = yaffsfs_FindDevice(path,&dummy);
1897         return (void *)dev;
1898 }
1899
1900 int yaffs_mount2(const YCHAR *path,int read_only)
1901 {
1902         int retVal=-1;
1903         int result=YAFFS_FAIL;
1904         struct yaffs_dev *dev=NULL;
1905
1906         T(YAFFS_TRACE_MOUNT,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1907
1908         yaffsfs_Lock();
1909
1910         yaffsfs_InitHandles();
1911
1912         dev = yaffsfs_FindMountPoint(path);
1913         if(dev){
1914                 if(!dev->is_mounted){
1915                         dev->read_only = read_only ? 1 : 0;
1916                         result = yaffs_guts_initialise(dev);
1917                         if(result == YAFFS_FAIL)
1918                                 /* todo error - mount failed */
1919                                 yaffsfs_SetError(-ENOMEM);
1920                         retVal = result ? 0 : -1;
1921
1922                 }
1923                 else
1924                         /* todo error - already mounted. */
1925                         yaffsfs_SetError(-EBUSY);
1926         } else
1927                 /* todo error - no device */
1928                 yaffsfs_SetError(-ENODEV);
1929
1930         yaffsfs_Unlock();
1931         return retVal;
1932
1933 }
1934
1935 int yaffs_mount(const YCHAR *path)
1936 {
1937         return yaffs_mount2(path,0);
1938 }
1939
1940 int yaffs_sync(const YCHAR *path)
1941 {
1942         int retVal=-1;
1943         struct yaffs_dev *dev=NULL;
1944         YCHAR *dummy;
1945         
1946         yaffsfs_Lock();
1947         dev = yaffsfs_FindDevice(path,&dummy);
1948         if(dev){
1949                 if(dev->is_mounted){
1950                         
1951                         yaffs_flush_whole_cache(dev);
1952                         yaffs_checkpoint_save(dev);
1953                         retVal = 0;
1954                         
1955                 } else
1956                         /* todo error - not mounted. */
1957                         yaffsfs_SetError(-EINVAL);
1958                         
1959         }else
1960                 /* todo error - no device */
1961                 yaffsfs_SetError(-ENODEV);
1962
1963         yaffsfs_Unlock();
1964         return retVal;  
1965 }
1966
1967
1968 int yaffs_remount(const YCHAR *path, int force, int read_only)
1969 {
1970         int retVal=-1;
1971         struct yaffs_dev *dev=NULL;
1972         yaffsfs_Handle *yh;
1973
1974         yaffsfs_Lock();
1975         dev = yaffsfs_FindMountPoint(path);
1976         if(dev){
1977                 if(dev->is_mounted){
1978                         int i;
1979                         int inUse;
1980
1981                         yaffs_flush_whole_cache(dev);
1982
1983                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
1984                                 yh = & yaffsfs_handle[i];
1985                                 if(yh->useCount>0 && 
1986                                         yaffsfs_inode[yh->inodeId].iObj->my_dev == dev)
1987                                         inUse = 1; /* the device is in use, can't unmount */
1988                         }
1989
1990                         if(!inUse || force){
1991                                 if(read_only)
1992                                         yaffs_checkpoint_save(dev);
1993                                 dev->read_only =  read_only ? 1 : 0;
1994                                 retVal = 0;
1995                         } else
1996                                 yaffsfs_SetError(-EBUSY);
1997
1998                 } else
1999                         yaffsfs_SetError(-EINVAL);
2000
2001         }
2002         else
2003                 yaffsfs_SetError(-ENODEV);
2004
2005         yaffsfs_Unlock();
2006         return retVal;
2007
2008 }
2009
2010 int yaffs_unmount2(const YCHAR *path, int force)
2011 {
2012         int retVal=-1;
2013         struct yaffs_dev *dev=NULL;
2014
2015         yaffsfs_Lock();
2016         dev = yaffsfs_FindMountPoint(path);
2017         if(dev){
2018                 if(dev->is_mounted){
2019                         int i;
2020                         int inUse;
2021
2022                         yaffs_flush_whole_cache(dev);
2023                         yaffs_checkpoint_save(dev);
2024
2025                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
2026                                 if(yaffsfs_handle[i].useCount > 0 && 
2027                                 yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->my_dev == dev)
2028                                         inUse = 1; /* the device is in use, can't unmount */
2029                         }
2030
2031                         if(!inUse || force){
2032                                 if(inUse)
2033                                         yaffsfs_PutDeviceHandles(dev);
2034                                 yaffs_deinitialise(dev);
2035
2036                                 retVal = 0;
2037                         } else
2038                                 /* todo error can't unmount as files are open */
2039                                 yaffsfs_SetError(-EBUSY);
2040
2041                 } else
2042                         /* todo error - not mounted. */
2043                         yaffsfs_SetError(-EINVAL);
2044
2045         } else
2046                 /* todo error - no device */
2047                 yaffsfs_SetError(-ENODEV);
2048
2049         yaffsfs_Unlock();
2050         return retVal;
2051
2052 }
2053
2054 int yaffs_unmount(const YCHAR *path)
2055 {
2056         return yaffs_unmount2(path,0);
2057 }
2058
2059 loff_t yaffs_freespace(const YCHAR *path)
2060 {
2061         loff_t retVal=-1;
2062         struct yaffs_dev *dev=NULL;
2063         YCHAR *dummy;
2064
2065         yaffsfs_Lock();
2066         dev = yaffsfs_FindDevice(path,&dummy);
2067         if(dev  && dev->is_mounted){
2068                 retVal = yaffs_get_n_free_chunks(dev);
2069                 retVal *= dev->data_bytes_per_chunk;
2070
2071         } else
2072                 yaffsfs_SetError(-EINVAL);
2073
2074         yaffsfs_Unlock();
2075         return retVal;
2076 }
2077
2078 loff_t yaffs_totalspace(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 = (dev->param.end_block - dev->param.start_block + 1) - dev->param.n_reserved_blocks;
2088                 retVal *= dev->param.chunks_per_block;
2089                 retVal *= dev->data_bytes_per_chunk;
2090
2091         } else
2092                 yaffsfs_SetError(-EINVAL);
2093
2094         yaffsfs_Unlock();
2095         return retVal;
2096 }
2097
2098 int yaffs_inodecount(const YCHAR *path)
2099 {
2100         loff_t retVal= -1;
2101         struct yaffs_dev *dev=NULL;
2102         YCHAR *dummy;
2103
2104         yaffsfs_Lock();
2105         dev = yaffsfs_FindDevice(path,&dummy);
2106         if(dev  && dev->is_mounted) {
2107            int n_obj = dev->n_obj;
2108            if(n_obj > dev->n_hardlinks)
2109                 retVal = n_obj - dev->n_hardlinks;
2110         }
2111         
2112         if(retVal < 0)
2113                 yaffsfs_SetError(-EINVAL);
2114         
2115         yaffsfs_Unlock();
2116         return retVal;  
2117 }
2118
2119
2120 void yaffs_add_device(struct yaffs_dev *dev)
2121 {
2122         dev->is_mounted = 0;
2123         dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
2124
2125         if(!dev->dev_list.next)
2126                 INIT_LIST_HEAD(&dev->dev_list);
2127
2128         list_add(&dev->dev_list,&yaffsfs_deviceList);
2129 }
2130
2131 void yaffs_remove_device(struct yaffs_dev *dev)
2132 {
2133         list_del_init(&dev->dev_list);
2134 }
2135
2136
2137
2138
2139 /* Directory search stuff. */
2140
2141 /*
2142  * Directory search context
2143  *
2144  * NB this is an opaque structure.
2145  */
2146
2147
2148 typedef struct
2149 {
2150         u32 magic;
2151         yaffs_dirent de;                /* directory entry being used by this dsc */
2152         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
2153         struct yaffs_obj *dirObj;           /* ptr to directory being searched */
2154         struct yaffs_obj *nextReturn;       /* obj to be returned by next readddir */
2155         int offset;
2156         struct list_head others;       
2157 } yaffsfs_DirectorySearchContext;
2158
2159
2160
2161 static struct list_head search_contexts;
2162
2163
2164 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
2165 {
2166         if(dsc &&
2167            dsc->dirObj &&
2168            dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2169
2170            dsc->offset = 0;
2171
2172            if( list_empty(&dsc->dirObj->variant.dir_variant.children))
2173                 dsc->nextReturn = NULL;
2174            else
2175                 dsc->nextReturn = list_entry(dsc->dirObj->variant.dir_variant.children.next,
2176                                                 struct yaffs_obj,siblings);
2177         } else {
2178                 /* Hey someone isn't playing nice! */
2179         }
2180 }
2181
2182 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
2183 {
2184         if(dsc &&
2185            dsc->dirObj &&
2186            dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2187
2188            if( dsc->nextReturn == NULL ||
2189                list_empty(&dsc->dirObj->variant.dir_variant.children))
2190                 dsc->nextReturn = NULL;
2191            else {
2192                    struct list_head *next = dsc->nextReturn->siblings.next;
2193
2194                    if( next == &dsc->dirObj->variant.dir_variant.children)
2195                         dsc->nextReturn = NULL; /* end of list */
2196                    else
2197                         dsc->nextReturn = list_entry(next,struct yaffs_obj,siblings);
2198            }
2199         } else {
2200                 /* Hey someone isn't playing nice! */
2201         }
2202 }
2203
2204 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
2205 {
2206
2207         struct list_head *i;
2208         yaffsfs_DirectorySearchContext *dsc;
2209
2210         /* if search contexts not initilised then skip */
2211         if(!search_contexts.next)
2212                 return;
2213
2214         /* Iterate through the directory search contexts.
2215          * If any are the one being removed, then advance the dsc to
2216          * the next one to prevent a hanging ptr.
2217          */
2218          list_for_each(i, &search_contexts) {
2219                 if (i) {
2220                         dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
2221                         if(dsc->nextReturn == obj)
2222                                 yaffsfs_DirAdvance(dsc);
2223                 }
2224         }
2225
2226 }
2227
2228 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
2229 {
2230         yaffs_DIR *dir = NULL;
2231         struct yaffs_obj *obj = NULL;
2232         yaffsfs_DirectorySearchContext *dsc = NULL;
2233
2234         yaffsfs_Lock();
2235
2236         obj = yaffsfs_FindObject(NULL,dirname,0,1,NULL);
2237
2238         if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2239
2240                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
2241                 dir = (yaffs_DIR *)dsc;
2242
2243                 if(dsc){
2244                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
2245                         dsc->magic = YAFFS_MAGIC;
2246                         dsc->dirObj = obj;
2247                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
2248                         INIT_LIST_HEAD(&dsc->others);
2249
2250                         if(!search_contexts.next)
2251                                 INIT_LIST_HEAD(&search_contexts);
2252
2253                         list_add(&dsc->others,&search_contexts);       
2254                         yaffsfs_SetDirRewound(dsc);
2255                 }
2256
2257         }
2258
2259         yaffsfs_Unlock();
2260
2261         return dir;
2262 }
2263
2264 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2265 {
2266         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2267         struct yaffs_dirent *retVal = NULL;
2268
2269         yaffsfs_Lock();
2270
2271         if(dsc && dsc->magic == YAFFS_MAGIC){
2272                 yaffsfs_SetError(0);
2273                 if(dsc->nextReturn){
2274                         dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
2275                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2276                         dsc->de.d_off = dsc->offset++;
2277                         yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2278                         if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2279                         {
2280                                 /* this should not happen! */
2281                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2282                         }
2283                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2284                         retVal = &dsc->de;
2285                         yaffsfs_DirAdvance(dsc);
2286                 } else
2287                         retVal = NULL;
2288         } else
2289                 yaffsfs_SetError(-EBADF);
2290
2291         yaffsfs_Unlock();
2292
2293         return retVal;
2294
2295 }
2296
2297
2298 void yaffs_rewinddir(yaffs_DIR *dirp)
2299 {
2300         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2301
2302         yaffsfs_Lock();
2303
2304         yaffsfs_SetDirRewound(dsc);
2305
2306         yaffsfs_Unlock();
2307 }
2308
2309
2310 int yaffs_closedir(yaffs_DIR *dirp)
2311 {
2312         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2313
2314         yaffsfs_Lock();
2315         dsc->magic = 0;
2316         list_del(&dsc->others); /* unhook from list */
2317         YFREE(dsc);
2318         yaffsfs_Unlock();
2319         return 0;
2320 }
2321
2322 /* End of directory stuff */
2323
2324
2325 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2326 {
2327         struct yaffs_obj *parent = NULL;
2328         struct yaffs_obj *obj;
2329         YCHAR *name;
2330         int retVal= -1;
2331         int mode = 0; /* ignore for now */
2332
2333         yaffsfs_Lock();
2334         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
2335         if(parent && parent->my_dev->read_only)
2336                 yaffsfs_SetError(-EINVAL);
2337         else if(parent){
2338                 obj = yaffs_create_symlink(parent,name,mode,0,0,oldpath);
2339                 if(obj)
2340                         retVal = 0;
2341                 else{
2342                         yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
2343                         retVal = -1;
2344                 }
2345         } else {
2346                 yaffsfs_SetError(-EINVAL);
2347                 retVal = -1;
2348         }
2349
2350         yaffsfs_Unlock();
2351
2352         return retVal;
2353
2354 }
2355
2356 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
2357 {
2358         struct yaffs_obj *obj = NULL;
2359         struct yaffs_obj *dir = NULL;
2360         int retVal= -1;
2361
2362         yaffsfs_Lock();
2363
2364         obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
2365
2366         if(!dir) 
2367                 yaffsfs_SetError(-ENOTDIR);
2368         else if(!obj) 
2369                 yaffsfs_SetError(-ENOENT);
2370         else if(obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
2371                 yaffsfs_SetError(-EINVAL);
2372         else {
2373                 YCHAR *alias = obj->variant.symlink_variant.alias;
2374                 memset(buf,0,bufsiz);
2375                 yaffs_strncpy(buf,alias,bufsiz - 1);
2376                 retVal = 0;
2377         }
2378         yaffsfs_Unlock();
2379         return retVal;
2380 }
2381
2382 int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
2383 {
2384         /* Creates a link called newpath to existing oldpath */
2385         struct yaffs_obj *obj = NULL;
2386         struct yaffs_obj *lnk = NULL;
2387         int retVal = -1;
2388
2389         yaffsfs_Lock();
2390
2391         obj = yaffsfs_FindObject(NULL,oldpath,0,1,NULL);
2392         lnk = yaffsfs_FindObject(NULL,linkpath,0,0,NULL);
2393
2394         if(!obj)
2395                 yaffsfs_SetError(-ENOENT);
2396         else if(obj->my_dev->read_only)
2397                 yaffsfs_SetError(-EINVAL);
2398         else if(lnk)
2399                 yaffsfs_SetError(-EEXIST);
2400         else {
2401                 struct yaffs_obj *newdir = NULL;
2402                 struct yaffs_obj *link = NULL;
2403
2404                 YCHAR *newname;
2405
2406                 newdir = yaffsfs_FindDirectory(NULL,linkpath,&newname,0);
2407
2408                 if(!newdir)
2409                         yaffsfs_SetError(-ENOTDIR);
2410                 else if(newdir->my_dev != obj->my_dev)
2411                         yaffsfs_SetError(-EXDEV);
2412                 
2413                 retVal = yaffsfs_CheckNameLength(newname);
2414                 
2415                 if(retVal == 0) {
2416                         link = yaffs_link_obj(newdir,newname,obj);
2417                         if(link)
2418                                 retVal = 0;
2419                         else{
2420                                 yaffsfs_SetError(-ENOSPC);
2421                                 retVal = -1;
2422                         }
2423
2424                 }
2425         }
2426         yaffsfs_Unlock();
2427
2428         return retVal;
2429 }
2430
2431 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
2432 {
2433         pathname=pathname;
2434         mode=mode;
2435         dev=dev;
2436         return -1;
2437 }
2438
2439
2440
2441 /*
2442  * yaffs_n_handles()
2443  * Returns number of handles attached to the object
2444  */
2445 int yaffs_n_handles(const YCHAR *path)
2446 {
2447         struct yaffs_obj *obj;
2448
2449         obj = yaffsfs_FindObject(NULL,path,0,1,NULL);
2450
2451         return yaffsfs_CountHandles(obj);
2452 }
2453
2454 int yaffs_get_error(void)
2455 {
2456         return yaffsfs_GetLastError();
2457 }
2458
2459 int yaffs_set_error(int error)
2460 {
2461         /*yaffsfs_SetError does not return. So the program is assumed to have worked. */
2462         yaffsfs_SetError(error);
2463         return 0;
2464 }
2465
2466 int yaffs_dump_dev(const YCHAR *path)
2467 {
2468 #if 1
2469         path=path;
2470 #else
2471         YCHAR *rest;
2472
2473         struct yaffs_obj *obj = yaffsfs_FindRoot(path,&rest);
2474
2475         if(obj){
2476                 struct yaffs_dev *dev = obj->my_dev;
2477
2478                 printf("\n"
2479                            "n_page_writes.......... %d\n"
2480                            "n_page_reads........... %d\n"
2481                            "n_erasures....... %d\n"
2482                            "n_gc_copies............ %d\n"
2483                            "garbageCollections... %d\n"
2484                            "passiveGarbageColl'ns %d\n"
2485                            "\n",
2486                                 dev->n_page_writes,
2487                                 dev->n_page_reads,
2488                                 dev->n_erasures,
2489                                 dev->n_gc_copies,
2490                                 dev->garbageCollections,
2491                                 dev->passiveGarbageCollections
2492                 );
2493
2494         }
2495
2496 #endif
2497         return 0;
2498 }
2499