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