Clean up code formatting
[yaffs2.git] / direct / yaffsfs.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 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 <string.h> // for memset
18 #include "yportenv.h"
19
20 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
21
22 #ifndef NULL
23 #define NULL ((void *)0)
24 #endif
25
26
27 const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.28 2009-10-19 23:42:55 charles Exp $";
28
29 // configurationList is the list of devices that are supported
30 static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
31
32
33 /* Some forward references */
34 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path, int symDepth);
35 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
36
37
38 // Handle management.
39 //
40
41
42 unsigned int yaffs_wr_attempts;
43
44 typedef struct{
45         __u8  inUse:1;          // this handle is in use
46         __u8  readOnly:1;       // this handle is read only
47         __u8  append:1;         // append only
48         __u8  exclusive:1;      // exclusive
49         __u32 position;         // current position in file
50         yaffs_Object *obj;      // the object
51 }yaffsfs_Handle;
52
53
54 static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
55
56 // yaffsfs_InitHandle
57 /// Inilitalise handles on start-up.
58 //
59 static int yaffsfs_InitHandles(void)
60 {
61         int i;
62         for(i = 0; i < YAFFSFS_N_HANDLES; i++){
63                 yaffsfs_handle[i].inUse = 0;
64                 yaffsfs_handle[i].obj = NULL;
65         }
66         return 0;
67 }
68
69 yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
70 {
71         if(h < 0 || h >= YAFFSFS_N_HANDLES)
72                 return NULL;
73
74         return &yaffsfs_handle[h];
75 }
76
77 yaffs_Object *yaffsfs_GetHandleObject(int handle)
78 {
79         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
80
81         if(h && h->inUse)
82                 return h->obj;
83
84         return NULL;
85 }
86
87
88 //yaffsfs_GetHandle
89 // Grab a handle (when opening a file)
90 //
91
92 static int yaffsfs_GetHandle(void)
93 {
94         int i;
95         yaffsfs_Handle *h;
96
97         for(i = 0; i < YAFFSFS_N_HANDLES; i++){
98                 h = yaffsfs_GetHandlePointer(i);
99                 if(!h){
100                         // todo bug: should never happen
101                 }
102                 if(!h->inUse){
103                         memset(h,0,sizeof(yaffsfs_Handle));
104                         h->inUse=1;
105                         return i;
106                 }
107         }
108         return -1;
109 }
110
111 // yaffs_PutHandle
112 // Let go of a handle (when closing a file)
113 //
114 static int yaffsfs_PutHandle(int handle)
115 {
116         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
117
118         if(h){
119                 h->inUse = 0;
120                 h->obj = NULL;
121         }
122         return 0;
123 }
124
125
126
127 // Stuff to search for a directory from a path
128
129
130 int yaffsfs_Match(YCHAR a, YCHAR b)
131 {
132         // case sensitive
133         return (a == b);
134 }
135
136 int yaffsfs_IsPathDivider(YCHAR ch)
137 {
138         YCHAR *str = YAFFS_PATH_DIVIDERS;
139
140         while(*str){
141                 if(*str == ch)
142                         return 1;
143                 str++;
144         }
145
146         return 0;
147 }
148
149 // yaffsfs_FindDevice
150 // yaffsfs_FindRoot
151 // Scan the configuration list to find the root.
152 // Curveballs: Should match paths that end in '/' too
153 // Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
154 static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
155 {
156         yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
157         const YCHAR *leftOver;
158         const YCHAR *p;
159         yaffs_Device *retval = NULL;
160         int thisMatchLength;
161         int longestMatch = -1;
162         int matching;
163
164         // Check all configs, choose the one that:
165         // 1) Actually matches a prefix (ie /a amd /abc will not match
166         // 2) Matches the longest.
167         while(cfg && cfg->prefix && cfg->dev){
168                 leftOver = path;
169                 p = cfg->prefix;
170                 thisMatchLength = 0;
171                 matching = 1;
172
173
174                 while(matching && *p && *leftOver){
175                         // Skip over any /s
176                         while(yaffsfs_IsPathDivider(*p))
177                               p++;
178
179                         // Skip over any /s
180                         while(yaffsfs_IsPathDivider(*leftOver))
181                               leftOver++;
182
183                         // Now match the text part
184                         while(matching &&
185                               *p && !yaffsfs_IsPathDivider(*p) &&
186                               *leftOver && !yaffsfs_IsPathDivider(*leftOver)){
187                                 if(yaffsfs_Match(*p,*leftOver)){
188                                         p++;
189                                         leftOver++;
190                                         thisMatchLength++;
191                                 } else {
192                                         matching = 0;
193                                 }
194                         }
195                 }
196
197                 // Skip over any /s in leftOver
198                 while(yaffsfs_IsPathDivider(*leftOver))
199                       leftOver++;
200                 
201
202                 if( matching && (thisMatchLength > longestMatch)){
203                         // Matched prefix
204                         *restOfPath = (YCHAR *)leftOver;
205                         retval = cfg->dev;
206                         longestMatch = thisMatchLength;
207                 }
208
209                 cfg++;
210         }
211         return retval;
212 }
213
214 #if 0
215 static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
216 {
217         yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
218         const YCHAR *leftOver;
219         const YCHAR *p;
220         yaffs_Device *retval = NULL;
221         int thisMatchLength;
222         int longestMatch = -1;
223
224         // Check all configs, choose the one that:
225         // 1) Actually matches a prefix (ie /a amd /abc will not match
226         // 2) Matches the longest.
227         while(cfg && cfg->prefix && cfg->dev){
228                 leftOver = path;
229                 p = cfg->prefix;
230                 thisMatchLength = 0;
231
232                 while(*p &&  //unmatched part of prefix
233                       !(yaffsfs_IsPathDivider(*p) && (p[1] == 0)) && // the rest of the prefix is not / (to catch / at end)
234                       *leftOver &&
235                       yaffsfs_Match(*p,*leftOver)){
236                         p++;
237                         leftOver++;
238                         thisMatchLength++;
239                 }
240
241
242                 if((!*p || (yaffsfs_IsPathDivider(*p) && (p[1] == 0))) &&      // end of prefix
243                    (!*leftOver || yaffsfs_IsPathDivider(*leftOver)) && // no more in this path name part
244                    (thisMatchLength > longestMatch)){
245                         // Matched prefix
246                         *restOfPath = (YCHAR *)leftOver;
247                         retval = cfg->dev;
248                         longestMatch = thisMatchLength;
249                 }
250                 cfg++;
251         }
252         return retval;
253 }
254 #endif
255
256 static yaffs_Object *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath)
257 {
258
259         yaffs_Device *dev;
260
261         dev= yaffsfs_FindDevice(path,restOfPath);
262         if(dev && dev->isMounted){
263                 return dev->rootDir;
264         }
265         return NULL;
266 }
267
268 static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth)
269 {
270
271         while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
272                 YCHAR *alias = obj->variant.symLinkVariant.alias;
273
274                 if(yaffsfs_IsPathDivider(*alias))
275                         // Starts with a /, need to scan from root up
276                         obj = yaffsfs_FindObject(NULL,alias,symDepth++);
277                 else
278                         // Relative to here, so use the parent of the symlink as a start
279                         obj = yaffsfs_FindObject(obj->parent,alias,symDepth++);
280         }
281         return obj;
282 }
283
284
285 // yaffsfs_FindDirectory
286 // Parse a path to determine the directory and the name within the directory.
287 //
288 // eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
289 static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const YCHAR *path,YCHAR **name,int symDepth)
290 {
291         yaffs_Object *dir;
292         YCHAR *restOfPath;
293         YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
294         int i;
295
296         if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
297                 return NULL;
298
299         if(startDir){
300                 dir = startDir;
301                 restOfPath = (YCHAR *)path;
302         }
303         else
304                 dir = yaffsfs_FindRoot(path,&restOfPath);
305
306         while(dir){
307                 // parse off /.
308                 // curve ball: also throw away surplus '/'
309                 // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
310                 while(yaffsfs_IsPathDivider(*restOfPath))
311                         restOfPath++; // get rid of '/'
312
313                 *name = restOfPath;
314                 i = 0;
315
316                 while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)){
317                         if (i < YAFFS_MAX_NAME_LENGTH){
318                                 str[i] = *restOfPath;
319                                 str[i+1] = '\0';
320                                 i++;
321                         }
322                         restOfPath++;
323                 }
324
325                 if(!*restOfPath)
326                         // got to the end of the string
327                         return dir;
328                 else{
329                         if(yaffs_strcmp(str,_Y(".")) == 0)
330                         {
331                                 // Do nothing
332                         }
333                         else if(yaffs_strcmp(str,_Y("..")) == 0)
334                                 dir = dir->parent;
335                         else{
336                                 dir = yaffs_FindObjectByName(dir,str);
337
338                                 while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
339                                         dir = yaffsfs_FollowLink(dir,symDepth);
340
341
342                                 if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
343                                         dir = NULL;
344                         }
345                 }
346         }
347         // directory did not exist.
348         return NULL;
349 }
350
351 static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const YCHAR *path,YCHAR **name,int symDepth)
352 {
353         return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
354 }
355
356 // yaffsfs_FindObject turns a path for an existing object into the object
357 //
358 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path,int symDepth)
359 {
360         yaffs_Object *dir;
361         YCHAR *name;
362
363         dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
364
365         if(dir && *name)
366                 return yaffs_FindObjectByName(dir,name);
367
368         return dir;
369 }
370
371
372 int yaffs_dup(int fd)
373 {
374         int newHandle = -1;
375         yaffsfs_Handle *oldPtr = NULL;
376         yaffsfs_Handle *newPtr = NULL;
377
378         yaffsfs_Lock();
379
380         oldPtr = yaffsfs_GetHandlePointer(fd);
381         if(oldPtr && oldPtr->inUse)
382                 newHandle = yaffsfs_GetHandle();
383         if(newHandle >= 0)
384                 newPtr = yaffsfs_GetHandlePointer(newHandle);
385
386         if(newPtr){
387                 *newPtr = *oldPtr;
388                 return newHandle;
389         }
390
391         if(!oldPtr)
392                 yaffsfs_SetError(-EBADF);
393         else
394                 yaffsfs_SetError(-ENOMEM);
395
396         return -1;
397
398 }
399
400 int yaffs_open(const YCHAR *path, int oflag, int mode)
401 {
402         yaffs_Object *obj = NULL;
403         yaffs_Object *dir = NULL;
404         YCHAR *name;
405         int handle = -1;
406         yaffsfs_Handle *h = NULL;
407         int alreadyOpen = 0;
408         int alreadyExclusive = 0;
409         int openDenied = 0;
410         int symDepth = 0;
411         int errorReported = 0;
412
413         int i;
414
415
416         // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR
417
418
419         yaffsfs_Lock();
420
421         handle = yaffsfs_GetHandle();
422
423         if(handle >= 0){
424
425                 h = yaffsfs_GetHandlePointer(handle);
426
427
428                 // try to find the exisiting object
429                 obj = yaffsfs_FindObject(NULL,path,0);
430
431                 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
432                         obj = yaffsfs_FollowLink(obj,symDepth++);
433
434                 if(obj && obj->variantType != YAFFS_OBJECT_TYPE_FILE)
435                         obj = NULL;
436
437                 if(obj){
438                         // Check if the object is already in use
439                         alreadyOpen = alreadyExclusive = 0;
440
441                         for(i = 0; i < YAFFSFS_N_HANDLES; i++){
442
443                                 if(i != handle &&
444                                    yaffsfs_handle[i].inUse &&
445                                     obj == yaffsfs_handle[i].obj){
446                                         alreadyOpen = 1;
447                                         if(yaffsfs_handle[i].exclusive)
448                                                 alreadyExclusive = 1;
449                                  }
450                         }
451
452                         if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive)
453                                 openDenied = 1;
454
455                         // Open should fail if O_CREAT and O_EXCL are specified
456                         if((oflag & O_EXCL) && (oflag & O_CREAT)){
457                                 openDenied = 1;
458                                 yaffsfs_SetError(-EEXIST);
459                                 errorReported = 1;
460                         }
461
462                         // Check file permissions
463                         if( (oflag & (O_RDWR | O_WRONLY)) == 0 &&     // ie O_RDONLY
464                            !(obj->yst_mode & S_IREAD))
465                                 openDenied = 1;
466
467                         if( (oflag & O_RDWR) &&
468                            !(obj->yst_mode & S_IREAD))
469                                 openDenied = 1;
470
471                         if( (oflag & (O_RDWR | O_WRONLY)) &&
472                            !(obj->yst_mode & S_IWRITE))
473                                 openDenied = 1;
474
475                 } else if((oflag & O_CREAT)) {
476                         // Let's see if we can create this file
477                         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
478                         if(dir)
479                                 obj = yaffs_MknodFile(dir,name,mode,0,0);
480                         else {
481                                 yaffsfs_SetError(-ENOTDIR);
482                                 errorReported = 1;
483                         }
484                 }
485
486                 if(obj && !openDenied) {
487                         h->obj = obj;
488                         h->inUse = 1;
489                         h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1;
490                         h->append =  (oflag & O_APPEND) ? 1 : 0;
491                         h->exclusive = (oflag & O_EXCL) ? 1 : 0;
492                         h->position = 0;
493
494                         obj->inUse++;
495                         if((oflag & O_TRUNC) && !h->readOnly)
496                                 yaffs_ResizeFile(obj,0);
497                 } else {
498                         yaffsfs_PutHandle(handle);
499                         if(!errorReported) {
500                                 yaffsfs_SetError(-EACCES);
501                                 errorReported = 1;
502                         }
503                         handle = -1;
504                 }
505         }
506
507         yaffsfs_Unlock();
508
509         return handle;
510 }
511
512 int yaffs_Dofsync(int fd,int datasync)
513 {
514         yaffsfs_Handle *h = NULL;
515         int retVal = 0;
516
517         yaffsfs_Lock();
518
519         h = yaffsfs_GetHandlePointer(fd);
520
521         if(h && h->inUse)
522                 // flush the file
523                 yaffs_FlushFile(h->obj,1,datasync);
524         else {
525                 // bad handle
526                 yaffsfs_SetError(-EBADF);
527                 retVal = -1;
528         }
529
530         yaffsfs_Unlock();
531
532         return retVal;
533 }
534
535 int yaffs_fsync(int fd)
536 {
537         return yaffs_Dofsync(fd,0);
538 }
539
540 int yaffs_flush(int fd)
541 {
542         return yaffs_fsync(fd);
543 }
544
545 int yaffs_fdatasync(int fd)
546 {
547         return yaffs_Dofsync(fd,1);
548 }
549
550 int yaffs_close(int fd)
551 {
552         yaffsfs_Handle *h = NULL;
553         int retVal = 0;
554
555         yaffsfs_Lock();
556
557         h = yaffsfs_GetHandlePointer(fd);
558
559         if(h && h->inUse) {
560                 // clean up
561                 yaffs_FlushFile(h->obj,1,0);
562                 h->obj->inUse--;
563                 if(h->obj->inUse <= 0 && h->obj->unlinked)
564                         yaffs_DeleteObject(h->obj);
565
566                 yaffsfs_PutHandle(fd);
567                 retVal = 0;
568         } else {
569                 // bad handle
570                 yaffsfs_SetError(-EBADF);
571                 retVal = -1;
572         }
573
574         yaffsfs_Unlock();
575
576         return retVal;
577 }
578
579 int yaffs_read(int fd, void *buf, unsigned int nbyte)
580 {
581         yaffsfs_Handle *h = NULL;
582         yaffs_Object *obj = NULL;
583         int pos = 0;
584         int nRead = -1;
585         unsigned int maxRead;
586
587         yaffsfs_Lock();
588         h = yaffsfs_GetHandlePointer(fd);
589         obj = yaffsfs_GetHandleObject(fd);
590
591         if(!h || !obj)
592                 // bad handle
593                 yaffsfs_SetError(-EBADF);
594
595         else if( h && obj){
596                 pos=  h->position;
597                 if(yaffs_GetObjectFileLength(obj) > pos)
598                         maxRead = yaffs_GetObjectFileLength(obj) - pos;
599                 else
600                         maxRead = 0;
601
602                 if(nbyte > maxRead)
603                         nbyte = maxRead;
604
605
606                 if(nbyte > 0) {
607                         nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte);
608                         if(nRead >= 0)
609                                 h->position = pos + nRead;
610                         else {
611                                 //todo error
612                         }
613                 } else
614                         nRead = 0;
615
616         }
617
618         yaffsfs_Unlock();
619
620
621         return (nRead >= 0) ? nRead : -1;
622
623 }
624
625 int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
626 {
627         yaffsfs_Handle *h = NULL;
628         yaffs_Object *obj = NULL;
629         int pos = 0;
630         int nRead = -1;
631         unsigned int maxRead;
632
633         yaffsfs_Lock();
634         h = yaffsfs_GetHandlePointer(fd);
635         obj = yaffsfs_GetHandleObject(fd);
636
637         if(!h || !obj)
638                 // bad handle
639                 yaffsfs_SetError(-EBADF);
640         else if( h && obj) {
641                 pos= offset;
642                 if(yaffs_GetObjectFileLength(obj) > pos)
643                         maxRead = yaffs_GetObjectFileLength(obj) - pos;
644                 else
645                         maxRead = 0;
646
647                 if(nbyte > maxRead)
648                         nbyte = maxRead;
649
650
651                 if(nbyte > 0)
652                         nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte);
653                 else
654                         nRead = 0;
655         }
656
657         yaffsfs_Unlock();
658
659
660         return (nRead >= 0) ? nRead : -1;
661
662 }
663
664 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
665 {
666         yaffsfs_Handle *h = NULL;
667         yaffs_Object *obj = NULL;
668         int pos = 0;
669         int nWritten = -1;
670         int writeThrough = 0;
671
672         yaffsfs_Lock();
673         h = yaffsfs_GetHandlePointer(fd);
674         obj = yaffsfs_GetHandleObject(fd);
675
676         if(!h || !obj)
677                 // bad handle
678                 yaffsfs_SetError(-EBADF);
679         else if( h && obj && h->readOnly){
680                 // todo error
681         } else if( h && obj){
682                 if(h->append)
683                         pos =  yaffs_GetObjectFileLength(obj);
684                 else
685                         pos = h->position;
686
687                 nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough);
688
689                 if(nWritten >= 0)
690                         h->position = pos + nWritten;
691                 else {
692                         //todo error
693                 }
694
695         }
696
697         yaffsfs_Unlock();
698
699
700         return (nWritten >= 0) ? nWritten : -1;
701
702 }
703
704 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
705 {
706         yaffsfs_Handle *h = NULL;
707         yaffs_Object *obj = NULL;
708         int pos = 0;
709         int nWritten = -1;
710         int writeThrough = 0;
711
712         yaffsfs_Lock();
713         h = yaffsfs_GetHandlePointer(fd);
714         obj = yaffsfs_GetHandleObject(fd);
715
716         if(!h || !obj)
717                 // bad handle
718                 yaffsfs_SetError(-EBADF);
719         else if( h && obj && h->readOnly){
720                 // todo error
721         }
722         else if( h && obj){
723                 pos = offset;
724
725                 nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough);
726
727                 if(nWritten < 0 || ((unsigned int)nWritten) < nbyte)
728                         yaffsfs_SetError(-ENOSPC);
729
730         }
731
732         yaffsfs_Unlock();
733
734
735         return (nWritten >= 0) ? nWritten : -1;
736
737 }
738
739
740 int yaffs_truncate(const YCHAR *path,off_t newSize)
741 {
742         yaffs_Object *obj = NULL;
743         int result = YAFFS_FAIL;
744
745         yaffsfs_Lock();
746
747         obj = yaffsfs_FindObject(NULL,path,0);
748         if(obj)
749                 obj = yaffs_GetEquivalentObject(obj);
750
751         if(!obj)
752                 yaffsfs_SetError(-ENOENT);
753         else if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
754                 yaffsfs_SetError(-EISDIR);
755         else
756                 result = yaffs_ResizeFile(obj,newSize);
757
758         yaffsfs_Unlock();
759
760
761         return (result) ? 0 : -1;
762 }
763
764 int yaffs_ftruncate(int fd, off_t newSize)
765 {
766         yaffsfs_Handle *h = NULL;
767         yaffs_Object *obj = NULL;
768         int result = 0;
769
770         yaffsfs_Lock();
771         h = yaffsfs_GetHandlePointer(fd);
772         obj = yaffsfs_GetHandleObject(fd);
773
774         if(!h || !obj)
775                 // bad handle
776                 yaffsfs_SetError(-EBADF);
777         else
778                 // resize the file
779                 result = yaffs_ResizeFile(obj,newSize);
780         yaffsfs_Unlock();
781
782
783         return (result) ? 0 : -1;
784
785 }
786
787 off_t yaffs_lseek(int fd, off_t offset, int whence)
788 {
789         yaffsfs_Handle *h = NULL;
790         yaffs_Object *obj = NULL;
791         int pos = -1;
792         int fSize = -1;
793
794         yaffsfs_Lock();
795         h = yaffsfs_GetHandlePointer(fd);
796         obj = yaffsfs_GetHandleObject(fd);
797
798         if(!h || !obj)
799                 // bad handle
800                 yaffsfs_SetError(-EBADF);
801         else if(whence == SEEK_SET){
802                 if(offset >= 0)
803                         pos = offset;
804         }
805         else if(whence == SEEK_CUR) {
806                 if( (h->position + offset) >= 0)
807                         pos = (h->position + offset);
808         }
809         else if(whence == SEEK_END) {
810                 fSize = yaffs_GetObjectFileLength(obj);
811                 if(fSize >= 0 && (fSize + offset) >= 0)
812                         pos = fSize + offset;
813         }
814
815         if(pos >= 0)
816                 h->position = pos;
817         else {
818                 // todo error
819         }
820
821
822         yaffsfs_Unlock();
823
824         return pos;
825 }
826
827
828 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
829 {
830         yaffs_Object *dir = NULL;
831         yaffs_Object *obj = NULL;
832         YCHAR *name;
833         int result = YAFFS_FAIL;
834
835         yaffsfs_Lock();
836
837         obj = yaffsfs_FindObject(NULL,path,0);
838         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
839         if(!dir)
840                 yaffsfs_SetError(-ENOTDIR);
841         else if(!obj)
842                 yaffsfs_SetError(-ENOENT);
843         else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
844                 yaffsfs_SetError(-EISDIR);
845         else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
846                 yaffsfs_SetError(-ENOTDIR);
847         else {
848                 result = yaffs_Unlink(dir,name);
849
850                 if(result == YAFFS_FAIL && isDirectory)
851                         yaffsfs_SetError(-ENOTEMPTY);
852         }
853
854         yaffsfs_Unlock();
855
856         // todo error
857
858         return (result == YAFFS_FAIL) ? -1 : 0;
859 }
860
861
862 int yaffs_rmdir(const YCHAR *path)
863 {
864         return yaffsfs_DoUnlink(path,1);
865 }
866
867 int yaffs_unlink(const YCHAR *path)
868 {
869         return yaffsfs_DoUnlink(path,0);
870 }
871
872 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
873 {
874         yaffs_Object *olddir = NULL;
875         yaffs_Object *newdir = NULL;
876         yaffs_Object *obj = NULL;
877         YCHAR *oldname;
878         YCHAR *newname;
879         int result= YAFFS_FAIL;
880         int renameAllowed = 1;
881
882         yaffsfs_Lock();
883
884         olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
885         newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
886         obj = yaffsfs_FindObject(NULL,oldPath,0);
887
888         if(!olddir || !newdir || !obj) {
889                 // bad file
890                 yaffsfs_SetError(-EBADF);
891                 renameAllowed = 0;
892         } else if(olddir->myDev != newdir->myDev) {
893                 // oops must be on same device
894                 // todo error
895                 yaffsfs_SetError(-EXDEV);
896                 renameAllowed = 0;
897         } else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
898                 // It is a directory, check that it is not being renamed to
899                 // being its own decendent.
900                 // Do this by tracing from the new directory back to the root, checking for obj
901
902                 yaffs_Object *xx = newdir;
903
904                 while( renameAllowed && xx){
905                         if(xx == obj)
906                                 renameAllowed = 0;
907                         xx = xx->parent;
908                 }
909                 if(!renameAllowed)
910                         yaffsfs_SetError(-EACCES);
911         }
912
913         if(renameAllowed)
914                 result = yaffs_RenameObject(olddir,oldname,newdir,newname);
915
916         yaffsfs_Unlock();
917
918         return (result == YAFFS_FAIL) ? -1 : 0;
919 }
920
921
922 static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf)
923 {
924         int retVal = -1;
925
926         if(obj)
927                 obj = yaffs_GetEquivalentObject(obj);
928
929         if(obj && buf){
930                 buf->st_dev = (int)obj->myDev->genericDevice;
931                 buf->st_ino = obj->objectId;
932                 buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits
933
934                 if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
935                         buf->st_mode |= S_IFDIR;
936                 else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
937                         buf->st_mode |= S_IFLNK;
938                 else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
939                         buf->st_mode |= S_IFREG;
940
941                 buf->st_nlink = yaffs_GetObjectLinkCount(obj);
942                 buf->st_uid = 0;
943                 buf->st_gid = 0;;
944                 buf->st_rdev = obj->yst_rdev;
945                 buf->st_size = yaffs_GetObjectFileLength(obj);
946                 buf->st_blksize = obj->myDev->nDataBytesPerChunk;
947                 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
948 #if CONFIG_YAFFS_WINCE
949                 buf->yst_wince_atime[0] = obj->win_atime[0];
950                 buf->yst_wince_atime[1] = obj->win_atime[1];
951                 buf->yst_wince_ctime[0] = obj->win_ctime[0];
952                 buf->yst_wince_ctime[1] = obj->win_ctime[1];
953                 buf->yst_wince_mtime[0] = obj->win_mtime[0];
954                 buf->yst_wince_mtime[1] = obj->win_mtime[1];
955 #else
956                 buf->yst_atime = obj->yst_atime;
957                 buf->yst_ctime = obj->yst_ctime;
958                 buf->yst_mtime = obj->yst_mtime;
959 #endif
960                 retVal = 0;
961         }
962         return retVal;
963 }
964
965 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
966 {
967         yaffs_Object *obj;
968
969         int retVal = -1;
970
971         yaffsfs_Lock();
972         obj = yaffsfs_FindObject(NULL,path,0);
973
974         if(!doLStat && obj)
975                 obj = yaffsfs_FollowLink(obj,0);
976
977         if(obj)
978                 retVal = yaffsfs_DoStat(obj,buf);
979         else
980                 // todo error not found
981                 yaffsfs_SetError(-ENOENT);
982
983         yaffsfs_Unlock();
984
985         return retVal;
986
987 }
988
989 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
990 {
991         return yaffsfs_DoStatOrLStat(path,buf,0);
992 }
993
994 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
995 {
996         return yaffsfs_DoStatOrLStat(path,buf,1);
997 }
998
999 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1000 {
1001         yaffs_Object *obj;
1002
1003         int retVal = -1;
1004
1005         yaffsfs_Lock();
1006         obj = yaffsfs_GetHandleObject(fd);
1007
1008         if(obj)
1009                 retVal = yaffsfs_DoStat(obj,buf);
1010         else
1011                 // bad handle
1012                 yaffsfs_SetError(-EBADF);
1013
1014         yaffsfs_Unlock();
1015
1016         return retVal;
1017 }
1018
1019 #ifdef CONFIG_YAFFS_WINCE
1020 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1021 {
1022         yaffs_Object *obj;
1023
1024         int retVal = -1;
1025
1026         yaffsfs_Lock();
1027         obj = yaffsfs_GetHandleObject(fd);
1028
1029         if(obj){
1030
1031                 if(wctime){
1032                         wctime[0] = obj->win_ctime[0];
1033                         wctime[1] = obj->win_ctime[1];
1034                 }
1035                 if(watime){
1036                         watime[0] = obj->win_atime[0];
1037                         watime[1] = obj->win_atime[1];
1038                 }
1039                 if(wmtime){
1040                         wmtime[0] = obj->win_mtime[0];
1041                         wmtime[1] = obj->win_mtime[1];
1042                 }
1043
1044
1045                 retVal = 0;
1046         } else
1047                 // bad handle
1048                 yaffsfs_SetError(-EBADF);               
1049         
1050         yaffsfs_Unlock();
1051         
1052         return retVal;
1053 }
1054
1055
1056 int yaffs_set_wince_times(int fd, 
1057                                                   const unsigned *wctime, 
1058                                                   const unsigned *watime, 
1059                                                   const unsigned *wmtime)
1060 {
1061         yaffs_Object *obj;
1062         int result;
1063         int retVal = -1;
1064
1065         yaffsfs_Lock();
1066         obj = yaffsfs_GetHandleObject(fd);
1067
1068         if(obj){
1069
1070                 if(wctime){
1071                         obj->win_ctime[0] = wctime[0];
1072                         obj->win_ctime[1] = wctime[1];
1073                 }
1074                 if(watime){
1075                         obj->win_atime[0] = watime[0];
1076                         obj->win_atime[1] = watime[1];
1077                 }
1078                 if(wmtime){
1079                         obj->win_mtime[0] = wmtime[0];
1080                         obj->win_mtime[1] = wmtime[1];
1081                 }
1082
1083                 obj->dirty = 1;
1084                 result = yaffs_FlushFile(obj,0,0);
1085                 retVal = 0;
1086         } else
1087                 // bad handle
1088                 yaffsfs_SetError(-EBADF);
1089
1090         yaffsfs_Unlock();
1091
1092         return retVal;
1093 }
1094
1095 #endif
1096
1097
1098 static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
1099 {
1100         int result = -1;
1101
1102         if(obj)
1103                 obj = yaffs_GetEquivalentObject(obj);
1104
1105         if(obj) {
1106                 obj->yst_mode = mode;
1107                 obj->dirty = 1;
1108                 result = yaffs_FlushFile(obj,0,0);
1109         }
1110
1111         return result == YAFFS_OK ? 0 : -1;
1112 }
1113
1114
1115 int yaffs_access(const YCHAR *path, int amode)
1116 {
1117         yaffs_Object *obj;
1118
1119         int retval = 0;
1120
1121         yaffsfs_Lock();
1122         obj = yaffsfs_FindObject(NULL,path,0);
1123
1124         if(obj) {
1125                 int access_ok = 1;
1126
1127                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1128                         access_ok = 0;
1129                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1130                         access_ok = 0;
1131                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1132                         access_ok = 0;
1133
1134                 if(!access_ok) {
1135                         yaffsfs_SetError(-EACCES);
1136                         retval = -1;
1137                 }
1138         } else {
1139                 // todo error not found
1140                 yaffsfs_SetError(-ENOENT);
1141                 retval = -1;
1142         }
1143
1144         yaffsfs_Unlock();
1145
1146         return retval;
1147
1148 }
1149
1150
1151 int yaffs_chmod(const YCHAR *path, mode_t mode)
1152 {
1153         yaffs_Object *obj;
1154
1155         int retVal = -1;
1156
1157         yaffsfs_Lock();
1158         obj = yaffsfs_FindObject(NULL,path,0);
1159
1160         if(obj)
1161                 retVal = yaffsfs_DoChMod(obj,mode);
1162         else
1163                 // todo error not found
1164                 yaffsfs_SetError(-ENOENT);
1165
1166         yaffsfs_Unlock();
1167
1168         return retVal;
1169
1170 }
1171
1172
1173 int yaffs_fchmod(int fd, mode_t mode)
1174 {
1175         yaffs_Object *obj;
1176
1177         int retVal = -1;
1178
1179         yaffsfs_Lock();
1180         obj = yaffsfs_GetHandleObject(fd);
1181
1182         if(obj)
1183                 retVal = yaffsfs_DoChMod(obj,mode);
1184         else
1185                 // bad handle
1186                 yaffsfs_SetError(-EBADF);
1187
1188         yaffsfs_Unlock();
1189
1190         return retVal;
1191 }
1192
1193
1194 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1195 {
1196         yaffs_Object *parent = NULL;
1197         yaffs_Object *dir = NULL;
1198         YCHAR *name;
1199         int retVal= -1;
1200
1201         yaffsfs_Lock();
1202         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1203         if(parent)
1204                 dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1205         if(dir)
1206                 retVal = 0;
1207         else {
1208                 if(!parent)
1209                         yaffsfs_SetError(-ENOENT); // missing path
1210                 else if (yaffs_FindObjectByName(parent,name))
1211                         yaffsfs_SetError(-EEXIST); // the name already exists
1212                 else
1213                         yaffsfs_SetError(-ENOSPC); // just assume no space
1214                 retVal = -1;
1215         }
1216
1217         yaffsfs_Unlock();
1218
1219         return retVal;
1220 }
1221
1222 int yaffs_mount(const YCHAR *path)
1223 {
1224         int retVal=-1;
1225         int result=YAFFS_FAIL;
1226         yaffs_Device *dev=NULL;
1227         YCHAR *dummy;
1228
1229         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1230
1231         yaffsfs_Lock();
1232         dev = yaffsfs_FindDevice(path,&dummy);
1233         if(dev){
1234                 if(!dev->isMounted){
1235                         result = yaffs_GutsInitialise(dev);
1236                         if(result == YAFFS_FAIL)
1237                                 // todo error - mount failed
1238                                 yaffsfs_SetError(-ENOMEM);
1239                         retVal = result ? 0 : -1;
1240
1241                 }
1242                 else
1243                         //todo error - already mounted.
1244                         yaffsfs_SetError(-EBUSY);
1245         } else
1246                 // todo error - no device
1247                 yaffsfs_SetError(-ENODEV);
1248
1249         yaffsfs_Unlock();
1250         return retVal;
1251
1252 }
1253
1254 int yaffs_sync(const YCHAR *path)
1255 {
1256         int retVal=-1;
1257         yaffs_Device *dev=NULL;
1258         YCHAR *dummy;
1259         
1260         yaffsfs_Lock();
1261         dev = yaffsfs_FindDevice(path,&dummy);
1262         if(dev){
1263                 if(dev->isMounted){
1264                         
1265                         yaffs_FlushEntireDeviceCache(dev);
1266                         yaffs_CheckpointSave(dev);
1267                         
1268                         
1269                 } else
1270                         //todo error - not mounted.
1271                         yaffsfs_SetError(-EINVAL);
1272                         
1273         }else
1274                 // todo error - no device
1275                 yaffsfs_SetError(-ENODEV);
1276
1277         yaffsfs_Unlock();
1278         return retVal;  
1279 }
1280
1281
1282 int yaffs_unmount(const YCHAR *path)
1283 {
1284         int retVal=-1;
1285         yaffs_Device *dev=NULL;
1286         YCHAR *dummy;
1287
1288         yaffsfs_Lock();
1289         dev = yaffsfs_FindDevice(path,&dummy);
1290         if(dev){
1291                 if(dev->isMounted){
1292                         int i;
1293                         int inUse;
1294
1295                         yaffs_FlushEntireDeviceCache(dev);
1296                         yaffs_CheckpointSave(dev);
1297
1298                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
1299                                 if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev)
1300                                         inUse = 1; // the device is in use, can't unmount
1301                         }
1302
1303                         if(!inUse){
1304                                 yaffs_Deinitialise(dev);
1305
1306                                 retVal = 0;
1307                         } else
1308                                 // todo error can't unmount as files are open
1309                                 yaffsfs_SetError(-EBUSY);
1310
1311                 } else
1312                         //todo error - not mounted.
1313                         yaffsfs_SetError(-EINVAL);
1314
1315         }
1316         else
1317                 // todo error - no device
1318                 yaffsfs_SetError(-ENODEV);
1319
1320         yaffsfs_Unlock();
1321         return retVal;
1322
1323 }
1324
1325 loff_t yaffs_freespace(const YCHAR *path)
1326 {
1327         loff_t retVal=-1;
1328         yaffs_Device *dev=NULL;
1329         YCHAR *dummy;
1330
1331         yaffsfs_Lock();
1332         dev = yaffsfs_FindDevice(path,&dummy);
1333         if(dev  && dev->isMounted){
1334                 retVal = yaffs_GetNumberOfFreeChunks(dev);
1335                 retVal *= dev->nDataBytesPerChunk;
1336
1337         } else
1338                 yaffsfs_SetError(-EINVAL);
1339
1340         yaffsfs_Unlock();
1341         return retVal;
1342 }
1343
1344 loff_t yaffs_totalspace(const YCHAR *path)
1345 {
1346         loff_t retVal=-1;
1347         yaffs_Device *dev=NULL;
1348         YCHAR *dummy;
1349
1350         yaffsfs_Lock();
1351         dev = yaffsfs_FindDevice(path,&dummy);
1352         if(dev  && dev->isMounted){
1353                 retVal = (dev->endBlock - dev->startBlock + 1) - dev->nReservedBlocks;
1354                 retVal *= dev->nChunksPerBlock;
1355                 retVal *= dev->nDataBytesPerChunk;
1356
1357         } else
1358                 yaffsfs_SetError(-EINVAL);
1359
1360         yaffsfs_Unlock();
1361         return retVal;
1362 }
1363
1364 int yaffs_inodecount(const YCHAR *path)
1365 {
1366         loff_t retVal= -1;
1367         yaffs_Device *dev=NULL;
1368         YCHAR *dummy;
1369
1370         yaffsfs_Lock();
1371         dev = yaffsfs_FindDevice(path,&dummy);
1372         if(dev  && dev->isMounted) {
1373            int nObjects = dev->nObjectsCreated - dev->nFreeObjects;
1374            if(nObjects > dev->nHardLinks)
1375                 retVal = nObjects - dev->nHardLinks;
1376         }
1377         
1378         if(retVal < 0)
1379                 yaffsfs_SetError(-EINVAL);
1380         
1381         yaffsfs_Unlock();
1382         return retVal;  
1383 }
1384
1385
1386
1387 void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
1388 {
1389
1390         yaffsfs_DeviceConfiguration *cfg;
1391
1392         yaffsfs_configurationList = cfgList;
1393
1394         yaffsfs_InitHandles();
1395
1396         cfg = yaffsfs_configurationList;
1397
1398         while(cfg && cfg->prefix && cfg->dev){
1399                 cfg->dev->isMounted = 0;
1400                 cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback;
1401                 cfg++;
1402         }
1403
1404
1405 }
1406
1407
1408 //
1409 // Directory search stuff.
1410
1411 //
1412 // Directory search context
1413 //
1414 // NB this is an opaque structure.
1415
1416
1417 typedef struct
1418 {
1419         __u32 magic;
1420         yaffs_dirent de;                /* directory entry being used by this dsc */
1421         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
1422         yaffs_Object *dirObj;           /* ptr to directory being searched */
1423         yaffs_Object *nextReturn;       /* obj to be returned by next readddir */
1424         int offset;
1425         struct ylist_head others;       
1426 } yaffsfs_DirectorySearchContext;
1427
1428
1429
1430 static struct ylist_head search_contexts;
1431
1432
1433 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1434 {
1435         if(dsc &&
1436            dsc->dirObj &&
1437            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1438
1439            dsc->offset = 0;
1440
1441            if( ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1442                 dsc->nextReturn = NULL;
1443            else
1444                 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.directoryVariant.children.next,
1445                                                 yaffs_Object,siblings);
1446         } else {
1447                 /* Hey someone isn't playing nice! */
1448         }
1449 }
1450
1451 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1452 {
1453         if(dsc &&
1454            dsc->dirObj &&
1455            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1456
1457            if( dsc->nextReturn == NULL ||
1458                ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1459                 dsc->nextReturn = NULL;
1460            else {
1461                    struct ylist_head *next = dsc->nextReturn->siblings.next;
1462
1463                    if( next == &dsc->dirObj->variant.directoryVariant.children)
1464                         dsc->nextReturn = NULL; /* end of list */
1465                    else
1466                         dsc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
1467            }
1468         } else {
1469                 /* Hey someone isn't playing nice! */
1470         }
1471 }
1472
1473 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1474 {
1475
1476         struct ylist_head *i;
1477         yaffsfs_DirectorySearchContext *dsc;
1478
1479         /* if search contexts not initilised then skip */
1480         if(!search_contexts.next)
1481                 return;
1482
1483         /* Iterate through the directory search contexts.
1484          * If any are the one being removed, then advance the dsc to
1485          * the next one to prevent a hanging ptr.
1486          */
1487          ylist_for_each(i, &search_contexts) {
1488                 if (i) {
1489                         dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
1490                         if(dsc->nextReturn == obj)
1491                                 yaffsfs_DirAdvance(dsc);
1492                 }
1493         }
1494
1495 }
1496
1497 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
1498 {
1499         yaffs_DIR *dir = NULL;
1500         yaffs_Object *obj = NULL;
1501         yaffsfs_DirectorySearchContext *dsc = NULL;
1502
1503         yaffsfs_Lock();
1504
1505         obj = yaffsfs_FindObject(NULL,dirname,0);
1506
1507         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1508
1509                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1510                 dir = (yaffs_DIR *)dsc;
1511
1512                 if(dsc){
1513                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1514                         dsc->magic = YAFFS_MAGIC;
1515                         dsc->dirObj = obj;
1516                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
1517                         YINIT_LIST_HEAD(&dsc->others);
1518
1519                         if(!search_contexts.next)
1520                                 YINIT_LIST_HEAD(&search_contexts);
1521
1522                         ylist_add(&dsc->others,&search_contexts);       
1523                         yaffsfs_SetDirRewound(dsc);
1524                 }
1525
1526         }
1527
1528         yaffsfs_Unlock();
1529
1530         return dir;
1531 }
1532
1533 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
1534 {
1535         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1536         struct yaffs_dirent *retVal = NULL;
1537
1538         yaffsfs_Lock();
1539
1540         if(dsc && dsc->magic == YAFFS_MAGIC){
1541                 yaffsfs_SetError(0);
1542                 if(dsc->nextReturn){
1543                         dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
1544                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
1545                         dsc->de.d_off = dsc->offset++;
1546                         yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
1547                         if(yaffs_strlen(dsc->de.d_name) == 0)
1548                         {
1549                                 // this should not happen!
1550                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
1551                         }
1552                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
1553                         retVal = &dsc->de;
1554                         yaffsfs_DirAdvance(dsc);
1555                 } else
1556                         retVal = NULL;
1557         } else
1558                 yaffsfs_SetError(-EBADF);
1559
1560         yaffsfs_Unlock();
1561
1562         return retVal;
1563
1564 }
1565
1566
1567 void yaffs_rewinddir(yaffs_DIR *dirp)
1568 {
1569         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1570
1571         yaffsfs_Lock();
1572
1573         yaffsfs_SetDirRewound(dsc);
1574
1575         yaffsfs_Unlock();
1576 }
1577
1578
1579 int yaffs_closedir(yaffs_DIR *dirp)
1580 {
1581         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1582
1583         yaffsfs_Lock();
1584         dsc->magic = 0;
1585         ylist_del(&dsc->others); /* unhook from list */
1586         YFREE(dsc);
1587         yaffsfs_Unlock();
1588         return 0;
1589 }
1590
1591 // end of directory stuff
1592
1593
1594 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
1595 {
1596         yaffs_Object *parent = NULL;
1597         yaffs_Object *obj;
1598         YCHAR *name;
1599         int retVal= -1;
1600         int mode = 0; // ignore for now
1601
1602         yaffsfs_Lock();
1603         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
1604         if(parent){
1605                 obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
1606                 if(obj)
1607                         retVal = 0;
1608                 else{
1609                         yaffsfs_SetError(-ENOSPC); // just assume no space for now
1610                         retVal = -1;
1611                 }
1612         } else {
1613                 yaffsfs_SetError(-EINVAL);
1614                 retVal = -1;
1615         }
1616
1617         yaffsfs_Unlock();
1618
1619         return retVal;
1620
1621 }
1622
1623 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
1624 {
1625         yaffs_Object *obj = NULL;
1626         int retVal;
1627
1628
1629         yaffsfs_Lock();
1630
1631         obj = yaffsfs_FindObject(NULL,path,0);
1632
1633         if(!obj) {
1634                 yaffsfs_SetError(-ENOENT);
1635                 retVal = -1;
1636         } else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK) {
1637                 yaffsfs_SetError(-EINVAL);
1638                 retVal = -1;
1639         } else {
1640                 YCHAR *alias = obj->variant.symLinkVariant.alias;
1641                 memset(buf,0,bufsiz);
1642                 yaffs_strncpy(buf,alias,bufsiz - 1);
1643                 retVal = 0;
1644         }
1645         yaffsfs_Unlock();
1646         return retVal;
1647 }
1648
1649 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
1650 {
1651         // Creates a link called newpath to existing oldpath
1652         yaffs_Object *obj = NULL;
1653         yaffs_Object *target = NULL;
1654         int retVal = 0;
1655
1656
1657         yaffsfs_Lock();
1658
1659         obj = yaffsfs_FindObject(NULL,oldpath,0);
1660         target = yaffsfs_FindObject(NULL,newpath,0);
1661
1662         if(!obj) {
1663                 yaffsfs_SetError(-ENOENT);
1664                 retVal = -1;
1665         } else if(target) {
1666                 yaffsfs_SetError(-EEXIST);
1667                 retVal = -1;
1668         } else {
1669                 yaffs_Object *newdir = NULL;
1670                 yaffs_Object *link = NULL;
1671
1672                 YCHAR *newname;
1673
1674                 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
1675
1676                 if(!newdir){
1677                         yaffsfs_SetError(-ENOTDIR);
1678                         retVal = -1;
1679                 }else if(newdir->myDev != obj->myDev){
1680                         yaffsfs_SetError(-EXDEV);
1681                         retVal = -1;
1682                 }
1683
1684                 if(newdir && yaffs_strlen(newname) > 0) {
1685                         link = yaffs_Link(newdir,newname,obj);
1686                         if(link)
1687                                 retVal = 0;
1688                         else{
1689                                 yaffsfs_SetError(-ENOSPC);
1690                                 retVal = -1;
1691                         }
1692
1693                 }
1694         }
1695         yaffsfs_Unlock();
1696
1697         return retVal;
1698 }
1699
1700 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
1701 {
1702         return -1;
1703 }
1704
1705 int yaffs_DumpDevStruct(const YCHAR *path)
1706 {
1707 #if 0
1708         YCHAR *rest;
1709
1710         yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
1711
1712         if(obj){
1713                 yaffs_Device *dev = obj->myDev;
1714
1715                 printf("\n"
1716                            "nPageWrites.......... %d\n"
1717                            "nPageReads........... %d\n"
1718                            "nBlockErasures....... %d\n"
1719                            "nGCCopies............ %d\n"
1720                            "garbageCollections... %d\n"
1721                            "passiveGarbageColl'ns %d\n"
1722                            "\n",
1723                                 dev->nPageWrites,
1724                                 dev->nPageReads,
1725                                 dev->nBlockErasures,
1726                                 dev->nGCCopies,
1727                                 dev->garbageCollections,
1728                                 dev->passiveGarbageCollections
1729                 );
1730
1731         }
1732
1733 #endif
1734         return 0;
1735 }
1736