2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
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.
15 #include "yaffs_guts.h"
18 #include "yaffs_trace.h"
20 #include <string.h> /* for memset */
22 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
25 #define NULL ((void *)0)
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)
33 /* Some forward references */
34 static yaffs_obj_t *yaffsfs_FindObject(yaffs_obj_t *relativeDirectory, const YCHAR *path, int symDepth, int getEquiv);
35 static void yaffsfs_RemoveObjectCallback(yaffs_obj_t *obj);
37 unsigned int yaffs_wr_attempts;
41 * There are open inodes in yaffsfs_Inode.
42 * There are open handles in yaffsfs_Handle.
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.
51 int count; /* Number of handles accessing this inode */
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 */
66 static yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
67 static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
68 static int yaffsfs_handlesInitialised;
72 * Inilitalise handle management on start-up.
75 static void yaffsfs_InitHandles(void)
78 if(yaffsfs_handlesInitialised)
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;
87 yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
89 if(h < 0 || h >= YAFFSFS_N_HANDLES)
92 return &yaffsfs_handle[h];
95 yaffsfs_Inode *yaffsfs_GetInodePointer(int handle)
97 yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
99 if(h && h->useCount > 0 && h->inodeId >= 0 && h->inodeId < YAFFSFS_N_HANDLES)
100 return &yaffsfs_inode[h->inodeId];
105 yaffs_obj_t *yaffsfs_GetHandleObject(int handle)
107 yaffsfs_Inode *in = yaffsfs_GetInodePointer(handle);
116 * yaffsfs_FindInodeIdForObject
117 * Find the inode entry for an object, if it exists.
120 static int yaffsfs_FindInodeIdForObject(yaffs_obj_t *obj)
126 obj = yaffs_get_equivalent_obj(obj);
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)
137 * yaffsfs_GetInodeIdForObject
138 * Grab an inode entry when opening a new inode.
140 static int yaffsfs_GetInodeIdForObject(yaffs_obj_t *obj)
144 yaffsfs_Inode *in = NULL;
147 obj = yaffs_get_equivalent_obj(obj);
149 ret = yaffsfs_FindInodeIdForObject(obj);
151 for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
152 if(!yaffsfs_inode[i].iObj)
157 in = &yaffsfs_inode[ret];
169 static int yaffsfs_CountHandles(yaffs_obj_t *obj)
171 int i = yaffsfs_FindInodeIdForObject(obj);
174 return yaffsfs_inode[i].count;
179 static void yaffsfs_ReleaseInode(yaffsfs_Inode *in)
188 obj->my_inode = NULL;
193 static void yaffsfs_PutInode(int inodeId)
195 if(inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES){
196 yaffsfs_Inode *in = & yaffsfs_inode[inodeId];
199 yaffsfs_ReleaseInode(in);
206 * Grab a handle (when opening a file)
209 static int yaffsfs_GetNewHandle(void)
214 for(i = 0; i < YAFFSFS_N_HANDLES; i++){
215 h = yaffsfs_GetHandlePointer(i);
217 /* todo bug: should never happen */
220 memset(h,0,sizeof(yaffsfs_Handle));
231 * Increase use of handle when reading/writing a file
233 static int yaffsfs_GetHandle(int handle)
235 yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
237 if(h && h->useCount > 0){
245 * Let go of a handle when closing a file or aborting an open or
246 * ending a read or write.
248 static int yaffsfs_PutHandle(int handle)
250 yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
252 if(h && h->useCount > 0){
256 yaffsfs_PutInode(h->inodeId);
268 * Stuff to search for a directory from a path
272 int yaffsfs_Match(YCHAR a, YCHAR b)
278 int yaffsfs_IsPathDivider(YCHAR ch)
280 const YCHAR *str = YAFFS_PATH_DIVIDERS;
293 YLIST_HEAD(yaffsfs_deviceList);
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
302 static yaffs_dev_t *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
304 struct ylist_head *cfg;
305 const YCHAR *leftOver;
307 yaffs_dev_t *retval = NULL;
308 yaffs_dev_t *dev = NULL;
310 int longestMatch = -1;
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.
318 ylist_for_each(cfg, &yaffsfs_deviceList){
319 dev = ylist_entry(cfg, yaffs_dev_t, dev_list);
326 while(matching && *p && *leftOver){
327 /* Skip over any /s */
328 while(yaffsfs_IsPathDivider(*p))
331 /* Skip over any /s */
332 while(yaffsfs_IsPathDivider(*leftOver))
335 /* Now match the text part */
337 *p && !yaffsfs_IsPathDivider(*p) &&
338 *leftOver && !yaffsfs_IsPathDivider(*leftOver)){
339 if(yaffsfs_Match(*p,*leftOver)){
349 /* Skip over any /s in leftOver */
350 while(yaffsfs_IsPathDivider(*leftOver))
353 // Skip over any /s in p
354 while(yaffsfs_IsPathDivider(*p))
357 // p should now be at the end of the string (ie. fully matched)
361 if( matching && (thisMatchLength > longestMatch))
364 *restOfPath = (YCHAR *)leftOver;
366 longestMatch = thisMatchLength;
374 static yaffs_dev_t *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
376 yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
377 const YCHAR *leftOver;
379 yaffs_dev_t *retval = NULL;
381 int longestMatch = -1;
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.
388 while(cfg && cfg->prefix && cfg->dev){
393 while(*p && /* unmatched part of prefix */
394 !(yaffsfs_IsPathDivider(*p) && (p[1] == 0)) &&
395 *leftOver && yaffsfs_Match(*p,*leftOver)){
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)){
406 *restOfPath = (YCHAR *)leftOver;
408 longestMatch = thisMatchLength;
416 static yaffs_obj_t *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath)
421 dev= yaffsfs_FindDevice(path,restOfPath);
422 if(dev && dev->is_mounted){
423 return dev->root_dir;
428 static yaffs_obj_t *yaffsfs_FollowLink(yaffs_obj_t *obj,int symDepth)
432 obj = yaffs_get_equivalent_obj(obj);
434 while(obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){
435 YCHAR *alias = obj->variant.symlink_variant.alias;
437 if(yaffsfs_IsPathDivider(*alias))
438 /* Starts with a /, need to scan from root up */
439 obj = yaffsfs_FindObject(NULL,alias,symDepth++,1);
441 /* Relative to here, so use the parent of the symlink as a start */
442 obj = yaffsfs_FindObject(obj->parent,alias,symDepth++,1);
449 * yaffsfs_FindDirectory
450 * Parse a path to determine the directory and the name within the directory.
452 * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
454 static yaffs_obj_t *yaffsfs_DoFindDirectory(yaffs_obj_t *startDir,
455 const YCHAR *path, YCHAR **name, int symDepth)
459 YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
462 if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
467 restOfPath = (YCHAR *)path;
470 dir = yaffsfs_FindRoot(path,&restOfPath);
475 * curve ball: also throw away surplus '/'
476 * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
478 while(yaffsfs_IsPathDivider(*restOfPath))
479 restOfPath++; /* get rid of '/' */
484 while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)){
485 if (i < YAFFS_MAX_NAME_LENGTH){
486 str[i] = *restOfPath;
494 /* got to the end of the string */
497 if(yaffs_strcmp(str,_Y(".")) == 0)
501 else if(yaffs_strcmp(str,_Y("..")) == 0)
504 dir = yaffs_find_by_name(dir,str);
506 dir = yaffsfs_FollowLink(dir,symDepth);
508 if(dir && dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
513 /* directory did not exist. */
517 static yaffs_obj_t *yaffsfs_FindDirectory(yaffs_obj_t *relativeDirectory,
518 const YCHAR *path,YCHAR **name,int symDepth)
520 return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
524 * yaffsfs_FindObject turns a path for an existing object into the object
526 static yaffs_obj_t *yaffsfs_FindObject(yaffs_obj_t *relativeDirectory, const YCHAR *path,int symDepth, int getEquiv)
532 dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
535 obj = yaffs_find_by_name(dir,name);
540 obj = yaffs_get_equivalent_obj(obj);
546 int yaffs_dup(int fd)
549 yaffsfs_Handle *oldPtr = NULL;
550 yaffsfs_Handle *newPtr = NULL;
554 oldPtr = yaffsfs_GetHandlePointer(fd);
555 if(oldPtr && oldPtr->useCount > 0)
556 newHandle = yaffsfs_GetNewHandle();
558 newPtr = yaffsfs_GetHandlePointer(newHandle);
566 yaffsfs_SetError(-EBADF);
568 yaffsfs_SetError(-ENOMEM);
574 int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
576 yaffs_obj_t *obj = NULL;
577 yaffs_obj_t *dir = NULL;
580 yaffsfs_Handle *yh = NULL;
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;
593 /* O_EXCL only has meaning if O_CREAT is specified */
594 if(!(oflag & O_CREAT))
597 /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
598 if( (oflag & O_CREAT) & (oflag & O_EXCL))
601 /* Todo: Are there any more flag combos to sanitise ? */
606 handle = yaffsfs_GetNewHandle();
610 yh = yaffsfs_GetHandlePointer(handle);
612 /* try to find the exisiting object */
613 obj = yaffsfs_FindObject(NULL,path,0,1);
615 obj = yaffsfs_FollowLink(obj,symDepth++);
618 obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
619 obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
624 /* The file already exists or it might be a directory */
626 /* If it is a directory then we can't open it as a file */
627 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
629 yaffsfs_SetError(-EISDIR);
633 /* Open should fail if O_CREAT and O_EXCL are specified since
636 if((oflag & O_EXCL) && (oflag & O_CREAT)){
638 yaffsfs_SetError(-EEXIST);
642 /* Check file permissions */
643 if( (oflag & (O_RDWR | O_WRONLY)) == 0 && /* ie O_RDONLY */
644 !(obj->yst_mode & S_IREAD))
647 if( (oflag & O_RDWR) &&
648 !(obj->yst_mode & S_IREAD))
651 if( (oflag & (O_RDWR | O_WRONLY)) &&
652 !(obj->yst_mode & S_IWRITE))
655 /* Check sharing of an existing object. */
659 sharedReadAllowed = 1;
660 sharedWriteAllowed = 1;
663 for( i = 0; i < YAFFSFS_N_HANDLES; i++){
664 hx = &yaffsfs_handle[i];
665 if(hx->useCount > 0 &&
667 yaffsfs_inode[hx->inodeId].iObj == obj){
669 sharedReadAllowed = 0;
671 sharedWriteAllowed = 0;
679 readRequested = (oflag & (O_RDWR | O_RDONLY)) ? 1 : 0;
680 writeRequested = (oflag & (O_RDWR | O_WRONLY)) ? 1 : 0;
682 if((!sharedReadAllowed && readRequested)||
683 (!shareRead && alreadyReading) ||
684 (!sharedWriteAllowed && writeRequested) ||
685 (!shareWrite && alreadyWriting)){
687 yaffsfs_SetError(-EBUSY);
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->my_dev->read_only){
696 yaffsfs_SetError(-EINVAL);
699 obj = yaffs_create_file(dir,name,mode,0,0);
701 yaffsfs_SetError(-ENOTDIR);
706 if(obj && !openDenied) {
707 int inodeId = yaffsfs_GetInodeIdForObject(obj);
711 * Todo: Fix any problem if inodes run out, though that
712 * can't happen if the number of inode items >= number of handles.
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;
721 yh->shareRead = shareRead;
722 yh->shareWrite = shareWrite;
724 /* Hook inode to object */
725 obj->my_inode = (void*) &yaffsfs_inode[inodeId];
727 if((oflag & O_TRUNC) && yh->writing)
728 yaffs_resize_file(obj,0);
730 yaffsfs_PutHandle(handle);
732 yaffsfs_SetError(-EACCES);
744 int yaffs_open(const YCHAR *path, int oflag, int mode)
746 return yaffs_open_sharing(path, oflag, mode, YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
749 int yaffs_Dofsync(int fd,int datasync)
751 yaffsfs_Handle *h = NULL;
756 h = yaffsfs_GetHandlePointer(fd);
758 if(h && h->useCount > 0)
760 yaffs_flush_file(yaffsfs_inode[h->inodeId].iObj,1,datasync);
763 yaffsfs_SetError(-EBADF);
772 int yaffs_fsync(int fd)
774 return yaffs_Dofsync(fd,0);
777 int yaffs_flush(int fd)
779 return yaffs_fsync(fd);
782 int yaffs_fdatasync(int fd)
784 return yaffs_Dofsync(fd,1);
787 int yaffs_close(int fd)
789 yaffsfs_Handle *h = NULL;
794 h = yaffsfs_GetHandlePointer(fd);
796 if(h && h->useCount > 0) {
798 yaffs_flush_file(yaffsfs_inode[h->inodeId].iObj,1,0);
799 yaffsfs_PutHandle(fd);
803 yaffsfs_SetError(-EBADF);
814 int yaffsfs_do_read(int fd, void *vbuf, unsigned int nbyte, int isPread, int offset)
816 yaffsfs_Handle *h = NULL;
817 yaffs_obj_t *obj = NULL;
823 unsigned int maxRead;
824 __u8 *buf = (__u8 *)vbuf;
827 h = yaffsfs_GetHandlePointer(fd);
828 obj = yaffsfs_GetHandleObject(fd);
832 yaffsfs_SetError(-EBADF);
834 } else if( h && obj){
838 startPos = h->position;
842 if(yaffs_get_obj_length(obj) > pos)
843 maxRead = yaffs_get_obj_length(obj) - pos;
851 yaffsfs_GetHandle(fd);
854 nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
857 nRead = yaffs_file_rd(obj,buf,pos,nToRead);
868 nbyte = 0; /* no more to read */
878 yaffsfs_PutHandle(fd);
882 h->position = startPos + totalRead;
892 return (totalRead >= 0) ? totalRead : -1;
896 int yaffs_read(int fd, void *buf, unsigned int nbyte)
898 return yaffsfs_do_read(fd, buf, nbyte, 0, 0);
901 int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
903 return yaffsfs_do_read(fd, buf, nbyte, 1, offset);
906 int yaffsfs_do_write(int fd, const void *vbuf, unsigned int nbyte, int isPwrite, int offset)
908 yaffsfs_Handle *h = NULL;
909 yaffs_obj_t *obj = NULL;
913 int totalWritten = 0;
914 int write_trhrough = 0;
916 const __u8 *buf = (const __u8 *)vbuf;
919 h = yaffsfs_GetHandlePointer(fd);
920 obj = yaffsfs_GetHandleObject(fd);
924 yaffsfs_SetError(-EBADF);
926 } else if( h && obj && (!h->writing || obj->my_dev->read_only)){
927 yaffsfs_SetError(-EINVAL);
929 } else if( h && obj){
931 startPos = yaffs_get_obj_length(obj);
935 startPos = h->position;
937 yaffsfs_GetHandle(fd);
940 nToWrite = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
944 nWritten = yaffs_wr_file(obj,buf,pos,nToWrite,write_trhrough);
946 totalWritten += nWritten;
951 if(nWritten == nToWrite)
956 if(nWritten < 1 && totalWritten < 1){
957 yaffsfs_SetError(-ENOSPC);
967 yaffsfs_PutHandle(fd);
971 h->position = startPos + totalWritten;
980 return (totalWritten >= 0) ? totalWritten : -1;
983 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
985 return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
988 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
990 return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
994 int yaffs_truncate(const YCHAR *path,off_t new_size)
996 yaffs_obj_t *obj = NULL;
997 int result = YAFFS_FAIL;
1001 obj = yaffsfs_FindObject(NULL,path,0,1);
1004 yaffsfs_SetError(-ENOENT);
1005 else if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
1006 yaffsfs_SetError(-EISDIR);
1007 else if(obj->my_dev->read_only)
1008 yaffsfs_SetError(-EINVAL);
1010 result = yaffs_resize_file(obj,new_size);
1015 return (result) ? 0 : -1;
1018 int yaffs_ftruncate(int fd, off_t new_size)
1020 yaffsfs_Handle *h = NULL;
1021 yaffs_obj_t *obj = NULL;
1025 h = yaffsfs_GetHandlePointer(fd);
1026 obj = yaffsfs_GetHandleObject(fd);
1030 yaffsfs_SetError(-EBADF);
1031 else if(obj->my_dev->read_only)
1032 yaffsfs_SetError(-EINVAL);
1034 /* resize the file */
1035 result = yaffs_resize_file(obj,new_size);
1039 return (result) ? 0 : -1;
1043 off_t yaffs_lseek(int fd, off_t offset, int whence)
1045 yaffsfs_Handle *h = NULL;
1046 yaffs_obj_t *obj = NULL;
1051 h = yaffsfs_GetHandlePointer(fd);
1052 obj = yaffsfs_GetHandleObject(fd);
1056 yaffsfs_SetError(-EBADF);
1057 else if(whence == SEEK_SET){
1061 else if(whence == SEEK_CUR) {
1062 if( (h->position + offset) >= 0)
1063 pos = (h->position + offset);
1065 else if(whence == SEEK_END) {
1066 fSize = yaffs_get_obj_length(obj);
1067 if(fSize >= 0 && (fSize + offset) >= 0)
1068 pos = fSize + offset;
1084 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
1086 yaffs_obj_t *dir = NULL;
1087 yaffs_obj_t *obj = NULL;
1089 int result = YAFFS_FAIL;
1093 obj = yaffsfs_FindObject(NULL,path,0,0);
1094 dir = yaffsfs_FindDirectory(NULL,path,&name,0);
1096 yaffsfs_SetError(-ENOTDIR);
1098 yaffsfs_SetError(-ENOENT);
1099 else if(obj->my_dev->read_only)
1100 yaffsfs_SetError(-EINVAL);
1101 else if(!isDirectory && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1102 yaffsfs_SetError(-EISDIR);
1103 else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1104 yaffsfs_SetError(-ENOTDIR);
1106 result = yaffs_unlinker(dir,name);
1108 if(result == YAFFS_FAIL && isDirectory)
1109 yaffsfs_SetError(-ENOTEMPTY);
1116 return (result == YAFFS_FAIL) ? -1 : 0;
1120 int yaffs_rmdir(const YCHAR *path)
1122 return yaffsfs_DoUnlink(path,1);
1125 int yaffs_unlink(const YCHAR *path)
1127 return yaffsfs_DoUnlink(path,0);
1130 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1132 yaffs_obj_t *olddir = NULL;
1133 yaffs_obj_t *newdir = NULL;
1134 yaffs_obj_t *obj = NULL;
1137 int result= YAFFS_FAIL;
1138 int rename_allowed = 1;
1142 olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1143 newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1144 obj = yaffsfs_FindObject(NULL,oldPath,0,0);
1146 if(!olddir || !newdir || !obj) {
1148 yaffsfs_SetError(-EBADF);
1150 } else if(obj->my_dev->read_only){
1151 yaffsfs_SetError(-EINVAL);
1153 } else if(olddir->my_dev != newdir->my_dev) {
1154 /* oops must be on same device */
1156 yaffsfs_SetError(-EXDEV);
1158 } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
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
1165 yaffs_obj_t *xx = newdir;
1167 while( rename_allowed && xx){
1173 yaffsfs_SetError(-EACCES);
1177 result = yaffs_rename_obj(olddir,oldname,newdir,newname);
1181 return (result == YAFFS_FAIL) ? -1 : 0;
1185 static int yaffsfs_DoStat(yaffs_obj_t *obj,struct yaffs_stat *buf)
1189 obj = yaffs_get_equivalent_obj(obj);
1192 buf->st_dev = (int)obj->my_dev->os_context;
1193 buf->st_ino = obj->obj_id;
1194 buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
1196 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1197 buf->st_mode |= S_IFDIR;
1198 else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1199 buf->st_mode |= S_IFLNK;
1200 else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1201 buf->st_mode |= S_IFREG;
1203 buf->st_nlink = yaffs_get_obj_link_count(obj);
1206 buf->st_rdev = obj->yst_rdev;
1207 buf->st_size = yaffs_get_obj_length(obj);
1208 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
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];
1218 buf->yst_atime = obj->yst_atime;
1219 buf->yst_ctime = obj->yst_ctime;
1220 buf->yst_mtime = obj->yst_mtime;
1227 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1235 obj = yaffsfs_FindObject(NULL,path,0,1);
1238 obj = yaffsfs_FollowLink(obj,0);
1241 retVal = yaffsfs_DoStat(obj,buf);
1243 /* todo error not found */
1244 yaffsfs_SetError(-ENOENT);
1252 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1254 return yaffsfs_DoStatOrLStat(path,buf,0);
1257 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1259 return yaffsfs_DoStatOrLStat(path,buf,1);
1262 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1269 obj = yaffsfs_GetHandleObject(fd);
1272 retVal = yaffsfs_DoStat(obj,buf);
1275 yaffsfs_SetError(-EBADF);
1282 #ifndef CONFIG_YAFFS_WINCE
1283 /* xattrib functions */
1286 static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags, int follow)
1294 obj = yaffsfs_FindObject(NULL,path,0,1);
1297 obj = yaffsfs_FollowLink(obj,0);
1300 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1302 yaffsfs_SetError(retVal);
1306 /* todo error not found */
1307 yaffsfs_SetError(-ENOENT);
1315 int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1317 return yaffs_do_setxattr(path, name, data, size, flags, 1);
1320 int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1322 return yaffs_do_setxattr(path, name, data, size, flags, 0);
1327 int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
1334 obj = yaffsfs_GetHandleObject(fd);
1337 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1339 yaffsfs_SetError(retVal);
1344 yaffsfs_SetError(-EBADF);
1351 static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
1359 obj = yaffsfs_FindObject(NULL,path,0,1);
1362 obj = yaffsfs_FollowLink(obj,0);
1365 retVal = yaffs_get_xattrib(obj,name,data,size);
1367 yaffsfs_SetError(retVal);
1371 /* todo error not found */
1372 yaffsfs_SetError(-ENOENT);
1380 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1382 return yaffs_do_getxattr( path, name, data, size, 1);
1384 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1386 return yaffs_do_getxattr( path, name, data, size, 0);
1391 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1398 obj = yaffsfs_GetHandleObject(fd);
1401 retVal = yaffs_get_xattrib(obj,name,data,size);
1403 yaffsfs_SetError(retVal);
1408 yaffsfs_SetError(-EBADF);
1415 static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
1423 obj = yaffsfs_FindObject(NULL,path,0,1);
1426 obj = yaffsfs_FollowLink(obj,0);
1429 retVal = yaffs_list_xattrib(obj, data,size);
1431 yaffsfs_SetError(retVal);
1435 /* todo error not found */
1436 yaffsfs_SetError(-ENOENT);
1444 int yaffs_listxattr(const YCHAR *path, char *data, int size)
1446 return yaffs_do_listxattr(path, data, size, 1);
1449 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
1451 return yaffs_do_listxattr(path, data, size, 0);
1454 int yaffs_flistxattr(int fd, char *data, int size)
1461 obj = yaffsfs_GetHandleObject(fd);
1464 retVal = yaffs_list_xattrib(obj,data,size);
1466 yaffsfs_SetError(retVal);
1471 yaffsfs_SetError(-EBADF);
1478 static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
1486 obj = yaffsfs_FindObject(NULL,path,0,1);
1489 obj = yaffsfs_FollowLink(obj,0);
1492 retVal = yaffs_remove_xattrib(obj,name);
1494 yaffsfs_SetError(retVal);
1498 /* todo error not found */
1499 yaffsfs_SetError(-ENOENT);
1507 int yaffs_removexattr(const YCHAR *path, const char *name)
1509 return yaffs_do_removexattr(path, name, 1);
1512 int yaffs_lremovexattr(const YCHAR *path, const char *name)
1514 return yaffs_do_removexattr(path, name, 0);
1517 int yaffs_fremovexattr(int fd, const char *name)
1524 obj = yaffsfs_GetHandleObject(fd);
1527 retVal = yaffs_remove_xattrib(obj,name);
1529 yaffsfs_SetError(retVal);
1534 yaffsfs_SetError(-EBADF);
1542 #ifdef CONFIG_YAFFS_WINCE
1543 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1550 obj = yaffsfs_GetHandleObject(fd);
1555 wctime[0] = obj->win_ctime[0];
1556 wctime[1] = obj->win_ctime[1];
1559 watime[0] = obj->win_atime[0];
1560 watime[1] = obj->win_atime[1];
1563 wmtime[0] = obj->win_mtime[0];
1564 wmtime[1] = obj->win_mtime[1];
1571 yaffsfs_SetError(-EBADF);
1579 int yaffs_set_wince_times(int fd,
1580 const unsigned *wctime,
1581 const unsigned *watime,
1582 const unsigned *wmtime)
1589 obj = yaffsfs_GetHandleObject(fd);
1594 obj->win_ctime[0] = wctime[0];
1595 obj->win_ctime[1] = wctime[1];
1598 obj->win_atime[0] = watime[0];
1599 obj->win_atime[1] = watime[1];
1602 obj->win_mtime[0] = wmtime[0];
1603 obj->win_mtime[1] = wmtime[1];
1607 result = yaffs_flush_file(obj,0,0);
1611 yaffsfs_SetError(-EBADF);
1621 static int yaffsfs_DoChMod(yaffs_obj_t *obj,mode_t mode)
1626 obj = yaffs_get_equivalent_obj(obj);
1629 obj->yst_mode = mode;
1631 result = yaffs_flush_file(obj,0,0);
1634 return result == YAFFS_OK ? 0 : -1;
1638 int yaffs_access(const YCHAR *path, int amode)
1646 obj = yaffsfs_FindObject(NULL,path,0,1);
1651 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1653 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1655 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1659 yaffsfs_SetError(-EACCES);
1663 /* todo error not found */
1664 yaffsfs_SetError(-ENOENT);
1675 int yaffs_chmod(const YCHAR *path, mode_t mode)
1683 obj = yaffsfs_FindObject(NULL,path,0,1);
1686 yaffsfs_SetError(-ENOENT);
1687 else if(obj->my_dev->read_only)
1688 yaffsfs_SetError(-EINVAL);
1690 retVal = yaffsfs_DoChMod(obj,mode);
1699 int yaffs_fchmod(int fd, mode_t mode)
1706 obj = yaffsfs_GetHandleObject(fd);
1709 yaffsfs_SetError(-ENOENT);
1710 else if(obj->my_dev->read_only)
1711 yaffsfs_SetError(-EINVAL);
1713 retVal = yaffsfs_DoChMod(obj,mode);
1721 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1723 yaffs_obj_t *parent = NULL;
1724 yaffs_obj_t *dir = NULL;
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->my_dev->read_only){
1734 yaffsfs_SetError(-EINVAL);
1737 dir = yaffs_create_dir(parent,name,mode,0,0);
1742 yaffsfs_SetError(-ENOENT); /* missing path */
1743 else if (yaffs_find_by_name(parent,name))
1744 yaffsfs_SetError(-EEXIST); /* the name already exists */
1746 yaffsfs_SetError(-ENOSPC); /* just assume no space */
1756 void * yaffs_getdev(const YCHAR *path)
1758 yaffs_dev_t *dev=NULL;
1760 dev = yaffsfs_FindDevice(path,&dummy);
1764 int yaffs_mount2(const YCHAR *path,int read_only)
1767 int result=YAFFS_FAIL;
1768 yaffs_dev_t *dev=NULL;
1771 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1775 yaffsfs_InitHandles();
1777 dev = yaffsfs_FindDevice(path,&dummy);
1779 if(!dev->is_mounted){
1780 dev->read_only = read_only ? 1 : 0;
1781 result = yaffs_guts_initialise(dev);
1782 if(result == YAFFS_FAIL)
1783 /* todo error - mount failed */
1784 yaffsfs_SetError(-ENOMEM);
1785 retVal = result ? 0 : -1;
1789 /* todo error - already mounted. */
1790 yaffsfs_SetError(-EBUSY);
1792 /* todo error - no device */
1793 yaffsfs_SetError(-ENODEV);
1800 int yaffs_mount(const YCHAR *path)
1802 return yaffs_mount2(path,0);
1805 int yaffs_sync(const YCHAR *path)
1808 yaffs_dev_t *dev=NULL;
1812 dev = yaffsfs_FindDevice(path,&dummy);
1814 if(dev->is_mounted){
1816 yaffs_flush_whole_cache(dev);
1817 yaffs_checkpoint_save(dev);
1821 /* todo error - not mounted. */
1822 yaffsfs_SetError(-EINVAL);
1825 /* todo error - no device */
1826 yaffsfs_SetError(-ENODEV);
1833 int yaffs_remount(const YCHAR *path, int force, int read_only)
1836 yaffs_dev_t *dev=NULL;
1840 dev = yaffsfs_FindDevice(path,&dummy);
1842 if(dev->is_mounted){
1846 yaffs_flush_whole_cache(dev);
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->my_dev == dev)
1850 inUse = 1; /* the device is in use, can't unmount */
1853 if(!inUse || force){
1855 yaffs_checkpoint_save(dev);
1856 dev->read_only = read_only ? 1 : 0;
1859 yaffsfs_SetError(-EBUSY);
1862 yaffsfs_SetError(-EINVAL);
1866 yaffsfs_SetError(-ENODEV);
1873 int yaffs_unmount2(const YCHAR *path, int force)
1876 yaffs_dev_t *dev=NULL;
1880 dev = yaffsfs_FindDevice(path,&dummy);
1882 if(dev->is_mounted){
1886 yaffs_flush_whole_cache(dev);
1887 yaffs_checkpoint_save(dev);
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->my_dev == dev)
1891 inUse = 1; /* the device is in use, can't unmount */
1894 if(!inUse || force){
1895 yaffs_deinitialise(dev);
1899 /* todo error can't unmount as files are open */
1900 yaffsfs_SetError(-EBUSY);
1903 /* todo error - not mounted. */
1904 yaffsfs_SetError(-EINVAL);
1908 /* todo error - no device */
1909 yaffsfs_SetError(-ENODEV);
1916 int yaffs_unmount(const YCHAR *path)
1918 return yaffs_unmount2(path,0);
1921 loff_t yaffs_freespace(const YCHAR *path)
1924 yaffs_dev_t *dev=NULL;
1928 dev = yaffsfs_FindDevice(path,&dummy);
1929 if(dev && dev->is_mounted){
1930 retVal = yaffs_get_n_free_chunks(dev);
1931 retVal *= dev->data_bytes_per_chunk;
1934 yaffsfs_SetError(-EINVAL);
1940 loff_t yaffs_totalspace(const YCHAR *path)
1943 yaffs_dev_t *dev=NULL;
1947 dev = yaffsfs_FindDevice(path,&dummy);
1948 if(dev && dev->is_mounted){
1949 retVal = (dev->param.end_block - dev->param.start_block + 1) - dev->param.n_reserved_blocks;
1950 retVal *= dev->param.chunks_per_block;
1951 retVal *= dev->data_bytes_per_chunk;
1954 yaffsfs_SetError(-EINVAL);
1960 int yaffs_inodecount(const YCHAR *path)
1963 yaffs_dev_t *dev=NULL;
1967 dev = yaffsfs_FindDevice(path,&dummy);
1968 if(dev && dev->is_mounted) {
1969 int n_obj = dev->n_obj;
1970 if(n_obj > dev->n_hardlinks)
1971 retVal = n_obj - dev->n_hardlinks;
1975 yaffsfs_SetError(-EINVAL);
1982 void yaffs_add_device(yaffs_dev_t *dev)
1984 dev->is_mounted = 0;
1985 dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
1987 if(!dev->dev_list.next)
1988 YINIT_LIST_HEAD(&dev->dev_list);
1990 ylist_add(&dev->dev_list,&yaffsfs_deviceList);
1993 void yaffs_remove_device(yaffs_dev_t *dev)
1995 ylist_del_init(&dev->dev_list);
2001 /* Directory search stuff. */
2004 * Directory search context
2006 * NB this is an opaque structure.
2013 yaffs_dirent de; /* directory entry being used by this dsc */
2014 YCHAR name[NAME_MAX+1]; /* name of directory being searched */
2015 yaffs_obj_t *dirObj; /* ptr to directory being searched */
2016 yaffs_obj_t *nextReturn; /* obj to be returned by next readddir */
2018 struct ylist_head others;
2019 } yaffsfs_DirectorySearchContext;
2023 static struct ylist_head search_contexts;
2026 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
2030 dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2034 if( ylist_empty(&dsc->dirObj->variant.dir_variant.children))
2035 dsc->nextReturn = NULL;
2037 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.dir_variant.children.next,
2038 yaffs_obj_t,siblings);
2040 /* Hey someone isn't playing nice! */
2044 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
2048 dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2050 if( dsc->nextReturn == NULL ||
2051 ylist_empty(&dsc->dirObj->variant.dir_variant.children))
2052 dsc->nextReturn = NULL;
2054 struct ylist_head *next = dsc->nextReturn->siblings.next;
2056 if( next == &dsc->dirObj->variant.dir_variant.children)
2057 dsc->nextReturn = NULL; /* end of list */
2059 dsc->nextReturn = ylist_entry(next,yaffs_obj_t,siblings);
2062 /* Hey someone isn't playing nice! */
2066 static void yaffsfs_RemoveObjectCallback(yaffs_obj_t *obj)
2069 struct ylist_head *i;
2070 yaffsfs_DirectorySearchContext *dsc;
2072 /* if search contexts not initilised then skip */
2073 if(!search_contexts.next)
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.
2080 ylist_for_each(i, &search_contexts) {
2082 dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
2083 if(dsc->nextReturn == obj)
2084 yaffsfs_DirAdvance(dsc);
2090 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
2092 yaffs_DIR *dir = NULL;
2093 yaffs_obj_t *obj = NULL;
2094 yaffsfs_DirectorySearchContext *dsc = NULL;
2098 obj = yaffsfs_FindObject(NULL,dirname,0,1);
2100 if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2102 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
2103 dir = (yaffs_DIR *)dsc;
2106 memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
2107 dsc->magic = YAFFS_MAGIC;
2109 yaffs_strncpy(dsc->name,dirname,NAME_MAX);
2110 YINIT_LIST_HEAD(&dsc->others);
2112 if(!search_contexts.next)
2113 YINIT_LIST_HEAD(&search_contexts);
2115 ylist_add(&dsc->others,&search_contexts);
2116 yaffsfs_SetDirRewound(dsc);
2126 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2128 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2129 struct yaffs_dirent *retVal = NULL;
2133 if(dsc && dsc->magic == YAFFS_MAGIC){
2134 yaffsfs_SetError(0);
2135 if(dsc->nextReturn){
2136 dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
2137 dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2138 dsc->de.d_off = dsc->offset++;
2139 yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2140 if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2142 /* this should not happen! */
2143 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2145 dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2147 yaffsfs_DirAdvance(dsc);
2151 yaffsfs_SetError(-EBADF);
2160 void yaffs_rewinddir(yaffs_DIR *dirp)
2162 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2166 yaffsfs_SetDirRewound(dsc);
2172 int yaffs_closedir(yaffs_DIR *dirp)
2174 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2178 ylist_del(&dsc->others); /* unhook from list */
2184 /* End of directory stuff */
2187 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2189 yaffs_obj_t *parent = NULL;
2193 int mode = 0; /* ignore for now */
2196 parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
2197 if(parent && parent->my_dev->read_only)
2198 yaffsfs_SetError(-EINVAL);
2200 obj = yaffs_create_symlink(parent,name,mode,0,0,oldpath);
2204 yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
2208 yaffsfs_SetError(-EINVAL);
2218 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
2220 yaffs_obj_t *obj = NULL;
2226 obj = yaffsfs_FindObject(NULL,path,0,1);
2229 yaffsfs_SetError(-ENOENT);
2231 } else if(obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK) {
2232 yaffsfs_SetError(-EINVAL);
2235 YCHAR *alias = obj->variant.symlink_variant.alias;
2236 memset(buf,0,bufsiz);
2237 yaffs_strncpy(buf,alias,bufsiz - 1);
2244 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
2246 /* Creates a link called newpath to existing oldpath */
2247 yaffs_obj_t *obj = NULL;
2248 yaffs_obj_t *target = NULL;
2250 int new_nameLength = 0;
2255 obj = yaffsfs_FindObject(NULL,oldpath,0,1);
2256 target = yaffsfs_FindObject(NULL,newpath,0,0);
2259 yaffsfs_SetError(-ENOENT);
2261 } else if(obj->my_dev->read_only){
2262 yaffsfs_SetError(-EINVAL);
2265 yaffsfs_SetError(-EEXIST);
2268 yaffs_obj_t *newdir = NULL;
2269 yaffs_obj_t *link = NULL;
2273 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
2276 yaffsfs_SetError(-ENOTDIR);
2278 }else if(newdir->my_dev != obj->my_dev){
2279 yaffsfs_SetError(-EXDEV);
2283 new_nameLength = yaffs_strnlen(newname,YAFFS_MAX_NAME_LENGTH+1);
2285 if(new_nameLength == 0){
2286 yaffsfs_SetError(-ENOENT);
2288 } else if (new_nameLength > YAFFS_MAX_NAME_LENGTH){
2289 yaffsfs_SetError(-ENAMETOOLONG);
2294 link = yaffs_link_obj(newdir,newname,obj);
2298 yaffsfs_SetError(-ENOSPC);
2309 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
2318 * Returns number of handles attached to the object
2320 int yaffs_n_handles(const YCHAR *path)
2324 obj = yaffsfs_FindObject(NULL,path,0,1);
2326 return yaffsfs_CountHandles(obj);
2329 int yaffs_dump_dev(const YCHAR *path)
2334 yaffs_obj_t *obj = yaffsfs_FindRoot(path,&rest);
2337 yaffs_dev_t *dev = obj->my_dev;
2340 "n_page_writes.......... %d\n"
2341 "n_page_reads........... %d\n"
2342 "n_erasures....... %d\n"
2343 "n_gc_copies............ %d\n"
2344 "garbageCollections... %d\n"
2345 "passiveGarbageColl'ns %d\n"
2351 dev->garbageCollections,
2352 dev->passiveGarbageCollections