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);
576 int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
578 yaffs_obj_t *obj = NULL;
579 yaffs_obj_t *dir = NULL;
582 yaffsfs_Handle *yh = NULL;
585 int errorReported = 0;
586 int rwflags = oflag & ( O_RDWR | O_RDONLY | O_WRONLY);
587 __u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0;
588 __u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0;
589 __u8 sharedReadAllowed;
590 __u8 sharedWriteAllowed;
596 /* O_EXCL only has meaning if O_CREAT is specified */
597 if(!(oflag & O_CREAT))
600 /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
601 if( (oflag & O_CREAT) & (oflag & O_EXCL))
604 /* Todo: Are there any more flag combos to sanitise ? */
606 /* Figure out if reading or writing is requested */
608 readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0;
609 writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0;
613 handle = yaffsfs_GetNewHandle();
616 yaffsfs_SetError(-ENFILE);
620 yh = yaffsfs_GetHandlePointer(handle);
622 /* try to find the exisiting object */
623 obj = yaffsfs_FindObject(NULL,path,0,1);
625 obj = yaffsfs_FollowLink(obj,symDepth++);
628 obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
629 obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
634 /* The file already exists or it might be a directory */
636 /* If it is a directory then we can't open it as a file */
637 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
639 yaffsfs_SetError(-EISDIR);
643 /* Open should fail if O_CREAT and O_EXCL are specified since
646 if((oflag & O_EXCL) && (oflag & O_CREAT)){
648 yaffsfs_SetError(-EEXIST);
652 /* Check file permissions */
653 if( readRequested && !(obj->yst_mode & S_IREAD))
656 if( writeRequested && !(obj->yst_mode & S_IWRITE))
659 /* Check sharing of an existing object. */
663 sharedReadAllowed = 1;
664 sharedWriteAllowed = 1;
667 for( i = 0; i < YAFFSFS_N_HANDLES; i++){
668 hx = &yaffsfs_handle[i];
669 if(hx->useCount > 0 &&
671 yaffsfs_inode[hx->inodeId].iObj == obj){
673 sharedReadAllowed = 0;
675 sharedWriteAllowed = 0;
685 if((!sharedReadAllowed && readRequested)||
686 (!shareRead && alreadyReading) ||
687 (!sharedWriteAllowed && writeRequested) ||
688 (!shareWrite && alreadyWriting)){
690 yaffsfs_SetError(-EBUSY);
695 } else if((oflag & O_CREAT)) {
696 /* Let's see if we can create this file */
697 dir = yaffsfs_FindDirectory(NULL,path,&name,0);
698 if(dir && dir->my_dev->read_only){
699 yaffsfs_SetError(-EINVAL);
702 obj = yaffs_create_file(dir,name,mode,0,0);
704 yaffsfs_SetError(-ENOTDIR);
709 if(obj && !openDenied) {
710 int inodeId = yaffsfs_GetInodeIdForObject(obj);
714 * Todo: Fix any problem if inodes run out, though that
715 * can't happen if the number of inode items >= number of handles.
719 yh->inodeId = inodeId;
720 yh->reading = readRequested;
721 yh->writing = writeRequested;
722 yh->append = (oflag & O_APPEND) ? 1 : 0;
724 yh->shareRead = shareRead;
725 yh->shareWrite = shareWrite;
727 /* Hook inode to object */
728 obj->my_inode = (void*) &yaffsfs_inode[inodeId];
730 if((oflag & O_TRUNC) && yh->writing)
731 yaffs_resize_file(obj,0);
733 yaffsfs_PutHandle(handle);
735 yaffsfs_SetError(-EACCES);
747 int yaffs_open(const YCHAR *path, int oflag, int mode)
749 return yaffs_open_sharing(path, oflag, mode, YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
752 int yaffs_Dofsync(int fd,int datasync)
754 yaffsfs_Handle *h = NULL;
759 h = yaffsfs_GetHandlePointer(fd);
761 if(h && h->useCount > 0)
763 yaffs_flush_file(yaffsfs_inode[h->inodeId].iObj,1,datasync);
766 yaffsfs_SetError(-EBADF);
775 int yaffs_fsync(int fd)
777 return yaffs_Dofsync(fd,0);
780 int yaffs_flush(int fd)
782 return yaffs_fsync(fd);
785 int yaffs_fdatasync(int fd)
787 return yaffs_Dofsync(fd,1);
790 int yaffs_close(int fd)
792 yaffsfs_Handle *h = NULL;
797 h = yaffsfs_GetHandlePointer(fd);
799 if(h && h->useCount > 0) {
801 yaffs_flush_file(yaffsfs_inode[h->inodeId].iObj,1,0);
802 yaffsfs_PutHandle(fd);
806 yaffsfs_SetError(-EBADF);
817 int yaffsfs_do_read(int fd, void *vbuf, unsigned int nbyte, int isPread, int offset)
819 yaffsfs_Handle *h = NULL;
820 yaffs_obj_t *obj = NULL;
826 unsigned int maxRead;
827 __u8 *buf = (__u8 *)vbuf;
830 h = yaffsfs_GetHandlePointer(fd);
831 obj = yaffsfs_GetHandleObject(fd);
835 yaffsfs_SetError(-EBADF);
837 } else if(!h->reading){
838 /* Not a reading handle */
839 yaffsfs_SetError(-EINVAL);
845 startPos = h->position;
849 if(yaffs_get_obj_length(obj) > pos)
850 maxRead = yaffs_get_obj_length(obj) - pos;
858 yaffsfs_GetHandle(fd);
861 nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
864 nRead = yaffs_file_rd(obj,buf,pos,nToRead);
875 nbyte = 0; /* no more to read */
885 yaffsfs_PutHandle(fd);
889 h->position = startPos + totalRead;
899 return (totalRead >= 0) ? totalRead : -1;
903 int yaffs_read(int fd, void *buf, unsigned int nbyte)
905 return yaffsfs_do_read(fd, buf, nbyte, 0, 0);
908 int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
910 return yaffsfs_do_read(fd, buf, nbyte, 1, offset);
913 int yaffsfs_do_write(int fd, const void *vbuf, unsigned int nbyte, int isPwrite, int offset)
915 yaffsfs_Handle *h = NULL;
916 yaffs_obj_t *obj = NULL;
920 int totalWritten = 0;
921 int write_trhrough = 0;
923 const __u8 *buf = (const __u8 *)vbuf;
926 h = yaffsfs_GetHandlePointer(fd);
927 obj = yaffsfs_GetHandleObject(fd);
931 yaffsfs_SetError(-EBADF);
933 } else if( h && obj && (!h->writing || obj->my_dev->read_only)){
934 yaffsfs_SetError(-EINVAL);
938 startPos = yaffs_get_obj_length(obj);
942 startPos = h->position;
944 yaffsfs_GetHandle(fd);
947 nToWrite = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
951 nWritten = yaffs_wr_file(obj,buf,pos,nToWrite,write_trhrough);
953 totalWritten += nWritten;
958 if(nWritten == nToWrite)
963 if(nWritten < 1 && totalWritten < 1){
964 yaffsfs_SetError(-ENOSPC);
974 yaffsfs_PutHandle(fd);
978 h->position = startPos + totalWritten;
987 return (totalWritten >= 0) ? totalWritten : -1;
990 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
992 return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
995 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
997 return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
1001 int yaffs_truncate(const YCHAR *path,off_t new_size)
1003 yaffs_obj_t *obj = NULL;
1004 int result = YAFFS_FAIL;
1008 obj = yaffsfs_FindObject(NULL,path,0,1);
1011 yaffsfs_SetError(-ENOENT);
1012 else if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
1013 yaffsfs_SetError(-EISDIR);
1014 else if(obj->my_dev->read_only)
1015 yaffsfs_SetError(-EINVAL);
1017 result = yaffs_resize_file(obj,new_size);
1022 return (result) ? 0 : -1;
1025 int yaffs_ftruncate(int fd, off_t new_size)
1027 yaffsfs_Handle *h = NULL;
1028 yaffs_obj_t *obj = NULL;
1032 h = yaffsfs_GetHandlePointer(fd);
1033 obj = yaffsfs_GetHandleObject(fd);
1037 yaffsfs_SetError(-EBADF);
1038 else if(obj->my_dev->read_only)
1039 yaffsfs_SetError(-EINVAL);
1041 /* resize the file */
1042 result = yaffs_resize_file(obj,new_size);
1046 return (result) ? 0 : -1;
1050 off_t yaffs_lseek(int fd, off_t offset, int whence)
1052 yaffsfs_Handle *h = NULL;
1053 yaffs_obj_t *obj = NULL;
1058 h = yaffsfs_GetHandlePointer(fd);
1059 obj = yaffsfs_GetHandleObject(fd);
1063 yaffsfs_SetError(-EBADF);
1064 else if(whence == SEEK_SET){
1068 else if(whence == SEEK_CUR) {
1069 if( (h->position + offset) >= 0)
1070 pos = (h->position + offset);
1072 else if(whence == SEEK_END) {
1073 fSize = yaffs_get_obj_length(obj);
1074 if(fSize >= 0 && (fSize + offset) >= 0)
1075 pos = fSize + offset;
1091 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
1093 yaffs_obj_t *dir = NULL;
1094 yaffs_obj_t *obj = NULL;
1096 int result = YAFFS_FAIL;
1100 obj = yaffsfs_FindObject(NULL,path,0,0);
1101 dir = yaffsfs_FindDirectory(NULL,path,&name,0);
1103 yaffsfs_SetError(-ENOTDIR);
1105 yaffsfs_SetError(-ENOENT);
1106 else if(obj->my_dev->read_only)
1107 yaffsfs_SetError(-EINVAL);
1108 else if(!isDirectory && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1109 yaffsfs_SetError(-EISDIR);
1110 else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1111 yaffsfs_SetError(-ENOTDIR);
1113 result = yaffs_unlinker(dir,name);
1115 if(result == YAFFS_FAIL && isDirectory)
1116 yaffsfs_SetError(-ENOTEMPTY);
1123 return (result == YAFFS_FAIL) ? -1 : 0;
1127 int yaffs_rmdir(const YCHAR *path)
1129 return yaffsfs_DoUnlink(path,1);
1132 int yaffs_unlink(const YCHAR *path)
1134 return yaffsfs_DoUnlink(path,0);
1137 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1139 yaffs_obj_t *olddir = NULL;
1140 yaffs_obj_t *newdir = NULL;
1141 yaffs_obj_t *obj = NULL;
1144 int result= YAFFS_FAIL;
1145 int rename_allowed = 1;
1149 olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1150 newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1151 obj = yaffsfs_FindObject(NULL,oldPath,0,0);
1153 if(!olddir || !newdir || !obj) {
1155 yaffsfs_SetError(-EBADF);
1157 } else if(obj->my_dev->read_only){
1158 yaffsfs_SetError(-EINVAL);
1160 } else if(olddir->my_dev != newdir->my_dev) {
1161 /* oops must be on same device */
1163 yaffsfs_SetError(-EXDEV);
1165 } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1167 * It is a directory, check that it is not being renamed to
1168 * being its own decendent.
1169 * Do this by tracing from the new directory back to the root, checking for obj
1172 yaffs_obj_t *xx = newdir;
1174 while( rename_allowed && xx){
1180 yaffsfs_SetError(-EACCES);
1184 result = yaffs_rename_obj(olddir,oldname,newdir,newname);
1188 return (result == YAFFS_FAIL) ? -1 : 0;
1192 static int yaffsfs_DoStat(yaffs_obj_t *obj,struct yaffs_stat *buf)
1196 obj = yaffs_get_equivalent_obj(obj);
1199 buf->st_dev = (int)obj->my_dev->os_context;
1200 buf->st_ino = obj->obj_id;
1201 buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
1203 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1204 buf->st_mode |= S_IFDIR;
1205 else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1206 buf->st_mode |= S_IFLNK;
1207 else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1208 buf->st_mode |= S_IFREG;
1210 buf->st_nlink = yaffs_get_obj_link_count(obj);
1213 buf->st_rdev = obj->yst_rdev;
1214 buf->st_size = yaffs_get_obj_length(obj);
1215 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
1216 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1217 #if CONFIG_YAFFS_WINCE
1218 buf->yst_wince_atime[0] = obj->win_atime[0];
1219 buf->yst_wince_atime[1] = obj->win_atime[1];
1220 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1221 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1222 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1223 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1225 buf->yst_atime = obj->yst_atime;
1226 buf->yst_ctime = obj->yst_ctime;
1227 buf->yst_mtime = obj->yst_mtime;
1234 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1242 obj = yaffsfs_FindObject(NULL,path,0,1);
1245 obj = yaffsfs_FollowLink(obj,0);
1248 retVal = yaffsfs_DoStat(obj,buf);
1250 /* todo error not found */
1251 yaffsfs_SetError(-ENOENT);
1259 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1261 return yaffsfs_DoStatOrLStat(path,buf,0);
1264 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1266 return yaffsfs_DoStatOrLStat(path,buf,1);
1269 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1276 obj = yaffsfs_GetHandleObject(fd);
1279 retVal = yaffsfs_DoStat(obj,buf);
1282 yaffsfs_SetError(-EBADF);
1289 #ifndef CONFIG_YAFFS_WINCE
1290 /* xattrib functions */
1293 static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags, int follow)
1301 obj = yaffsfs_FindObject(NULL,path,0,1);
1304 obj = yaffsfs_FollowLink(obj,0);
1307 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1309 yaffsfs_SetError(retVal);
1313 /* todo error not found */
1314 yaffsfs_SetError(-ENOENT);
1322 int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1324 return yaffs_do_setxattr(path, name, data, size, flags, 1);
1327 int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1329 return yaffs_do_setxattr(path, name, data, size, flags, 0);
1334 int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
1341 obj = yaffsfs_GetHandleObject(fd);
1344 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1346 yaffsfs_SetError(retVal);
1351 yaffsfs_SetError(-EBADF);
1358 static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
1366 obj = yaffsfs_FindObject(NULL,path,0,1);
1369 obj = yaffsfs_FollowLink(obj,0);
1372 retVal = yaffs_get_xattrib(obj,name,data,size);
1374 yaffsfs_SetError(retVal);
1378 /* todo error not found */
1379 yaffsfs_SetError(-ENOENT);
1387 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1389 return yaffs_do_getxattr( path, name, data, size, 1);
1391 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1393 return yaffs_do_getxattr( path, name, data, size, 0);
1398 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1405 obj = yaffsfs_GetHandleObject(fd);
1408 retVal = yaffs_get_xattrib(obj,name,data,size);
1410 yaffsfs_SetError(retVal);
1415 yaffsfs_SetError(-EBADF);
1422 static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
1430 obj = yaffsfs_FindObject(NULL,path,0,1);
1433 obj = yaffsfs_FollowLink(obj,0);
1436 retVal = yaffs_list_xattrib(obj, data,size);
1438 yaffsfs_SetError(retVal);
1442 /* todo error not found */
1443 yaffsfs_SetError(-ENOENT);
1451 int yaffs_listxattr(const YCHAR *path, char *data, int size)
1453 return yaffs_do_listxattr(path, data, size, 1);
1456 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
1458 return yaffs_do_listxattr(path, data, size, 0);
1461 int yaffs_flistxattr(int fd, char *data, int size)
1468 obj = yaffsfs_GetHandleObject(fd);
1471 retVal = yaffs_list_xattrib(obj,data,size);
1473 yaffsfs_SetError(retVal);
1478 yaffsfs_SetError(-EBADF);
1485 static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
1493 obj = yaffsfs_FindObject(NULL,path,0,1);
1496 obj = yaffsfs_FollowLink(obj,0);
1499 retVal = yaffs_remove_xattrib(obj,name);
1501 yaffsfs_SetError(retVal);
1505 /* todo error not found */
1506 yaffsfs_SetError(-ENOENT);
1514 int yaffs_removexattr(const YCHAR *path, const char *name)
1516 return yaffs_do_removexattr(path, name, 1);
1519 int yaffs_lremovexattr(const YCHAR *path, const char *name)
1521 return yaffs_do_removexattr(path, name, 0);
1524 int yaffs_fremovexattr(int fd, const char *name)
1531 obj = yaffsfs_GetHandleObject(fd);
1534 retVal = yaffs_remove_xattrib(obj,name);
1536 yaffsfs_SetError(retVal);
1541 yaffsfs_SetError(-EBADF);
1549 #ifdef CONFIG_YAFFS_WINCE
1550 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1557 obj = yaffsfs_GetHandleObject(fd);
1562 wctime[0] = obj->win_ctime[0];
1563 wctime[1] = obj->win_ctime[1];
1566 watime[0] = obj->win_atime[0];
1567 watime[1] = obj->win_atime[1];
1570 wmtime[0] = obj->win_mtime[0];
1571 wmtime[1] = obj->win_mtime[1];
1578 yaffsfs_SetError(-EBADF);
1586 int yaffs_set_wince_times(int fd,
1587 const unsigned *wctime,
1588 const unsigned *watime,
1589 const unsigned *wmtime)
1596 obj = yaffsfs_GetHandleObject(fd);
1601 obj->win_ctime[0] = wctime[0];
1602 obj->win_ctime[1] = wctime[1];
1605 obj->win_atime[0] = watime[0];
1606 obj->win_atime[1] = watime[1];
1609 obj->win_mtime[0] = wmtime[0];
1610 obj->win_mtime[1] = wmtime[1];
1614 result = yaffs_flush_file(obj,0,0);
1618 yaffsfs_SetError(-EBADF);
1628 static int yaffsfs_DoChMod(yaffs_obj_t *obj,mode_t mode)
1633 obj = yaffs_get_equivalent_obj(obj);
1636 obj->yst_mode = mode;
1638 result = yaffs_flush_file(obj,0,0);
1641 return result == YAFFS_OK ? 0 : -1;
1645 int yaffs_access(const YCHAR *path, int amode)
1653 obj = yaffsfs_FindObject(NULL,path,0,1);
1658 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1660 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1662 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1666 yaffsfs_SetError(-EACCES);
1670 /* todo error not found */
1671 yaffsfs_SetError(-ENOENT);
1682 int yaffs_chmod(const YCHAR *path, mode_t mode)
1690 obj = yaffsfs_FindObject(NULL,path,0,1);
1693 yaffsfs_SetError(-ENOENT);
1694 else if(obj->my_dev->read_only)
1695 yaffsfs_SetError(-EINVAL);
1697 retVal = yaffsfs_DoChMod(obj,mode);
1706 int yaffs_fchmod(int fd, mode_t mode)
1713 obj = yaffsfs_GetHandleObject(fd);
1716 yaffsfs_SetError(-ENOENT);
1717 else if(obj->my_dev->read_only)
1718 yaffsfs_SetError(-EINVAL);
1720 retVal = yaffsfs_DoChMod(obj,mode);
1728 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1730 yaffs_obj_t *parent = NULL;
1731 yaffs_obj_t *dir = NULL;
1736 parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1737 if(parent && yaffs_strnlen(name,5) == 0){
1738 /* Trying to make the root itself */
1739 yaffsfs_SetError(-EEXIST);
1740 } else if(parent && parent->my_dev->read_only){
1741 yaffsfs_SetError(-EINVAL);
1744 dir = yaffs_create_dir(parent,name,mode,0,0);
1749 yaffsfs_SetError(-ENOENT); /* missing path */
1750 else if (yaffs_find_by_name(parent,name))
1751 yaffsfs_SetError(-EEXIST); /* the name already exists */
1753 yaffsfs_SetError(-ENOSPC); /* just assume no space */
1763 void * yaffs_getdev(const YCHAR *path)
1765 yaffs_dev_t *dev=NULL;
1767 dev = yaffsfs_FindDevice(path,&dummy);
1771 int yaffs_mount2(const YCHAR *path,int read_only)
1774 int result=YAFFS_FAIL;
1775 yaffs_dev_t *dev=NULL;
1778 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1782 yaffsfs_InitHandles();
1784 dev = yaffsfs_FindDevice(path,&dummy);
1786 if(!dev->is_mounted){
1787 dev->read_only = read_only ? 1 : 0;
1788 result = yaffs_guts_initialise(dev);
1789 if(result == YAFFS_FAIL)
1790 /* todo error - mount failed */
1791 yaffsfs_SetError(-ENOMEM);
1792 retVal = result ? 0 : -1;
1796 /* todo error - already mounted. */
1797 yaffsfs_SetError(-EBUSY);
1799 /* todo error - no device */
1800 yaffsfs_SetError(-ENODEV);
1807 int yaffs_mount(const YCHAR *path)
1809 return yaffs_mount2(path,0);
1812 int yaffs_sync(const YCHAR *path)
1815 yaffs_dev_t *dev=NULL;
1819 dev = yaffsfs_FindDevice(path,&dummy);
1821 if(dev->is_mounted){
1823 yaffs_flush_whole_cache(dev);
1824 yaffs_checkpoint_save(dev);
1828 /* todo error - not mounted. */
1829 yaffsfs_SetError(-EINVAL);
1832 /* todo error - no device */
1833 yaffsfs_SetError(-ENODEV);
1840 int yaffs_remount(const YCHAR *path, int force, int read_only)
1843 yaffs_dev_t *dev=NULL;
1847 dev = yaffsfs_FindDevice(path,&dummy);
1849 if(dev->is_mounted){
1853 yaffs_flush_whole_cache(dev);
1855 for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
1856 if(yaffsfs_handle[i].useCount>0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->my_dev == dev)
1857 inUse = 1; /* the device is in use, can't unmount */
1860 if(!inUse || force){
1862 yaffs_checkpoint_save(dev);
1863 dev->read_only = read_only ? 1 : 0;
1866 yaffsfs_SetError(-EBUSY);
1869 yaffsfs_SetError(-EINVAL);
1873 yaffsfs_SetError(-ENODEV);
1880 int yaffs_unmount2(const YCHAR *path, int force)
1883 yaffs_dev_t *dev=NULL;
1887 dev = yaffsfs_FindDevice(path,&dummy);
1889 if(dev->is_mounted){
1893 yaffs_flush_whole_cache(dev);
1894 yaffs_checkpoint_save(dev);
1896 for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
1897 if(yaffsfs_handle[i].useCount > 0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->my_dev == dev)
1898 inUse = 1; /* the device is in use, can't unmount */
1901 if(!inUse || force){
1902 yaffs_deinitialise(dev);
1906 /* todo error can't unmount as files are open */
1907 yaffsfs_SetError(-EBUSY);
1910 /* todo error - not mounted. */
1911 yaffsfs_SetError(-EINVAL);
1915 /* todo error - no device */
1916 yaffsfs_SetError(-ENODEV);
1923 int yaffs_unmount(const YCHAR *path)
1925 return yaffs_unmount2(path,0);
1928 loff_t yaffs_freespace(const YCHAR *path)
1931 yaffs_dev_t *dev=NULL;
1935 dev = yaffsfs_FindDevice(path,&dummy);
1936 if(dev && dev->is_mounted){
1937 retVal = yaffs_get_n_free_chunks(dev);
1938 retVal *= dev->data_bytes_per_chunk;
1941 yaffsfs_SetError(-EINVAL);
1947 loff_t yaffs_totalspace(const YCHAR *path)
1950 yaffs_dev_t *dev=NULL;
1954 dev = yaffsfs_FindDevice(path,&dummy);
1955 if(dev && dev->is_mounted){
1956 retVal = (dev->param.end_block - dev->param.start_block + 1) - dev->param.n_reserved_blocks;
1957 retVal *= dev->param.chunks_per_block;
1958 retVal *= dev->data_bytes_per_chunk;
1961 yaffsfs_SetError(-EINVAL);
1967 int yaffs_inodecount(const YCHAR *path)
1970 yaffs_dev_t *dev=NULL;
1974 dev = yaffsfs_FindDevice(path,&dummy);
1975 if(dev && dev->is_mounted) {
1976 int n_obj = dev->n_obj;
1977 if(n_obj > dev->n_hardlinks)
1978 retVal = n_obj - dev->n_hardlinks;
1982 yaffsfs_SetError(-EINVAL);
1989 void yaffs_add_device(yaffs_dev_t *dev)
1991 dev->is_mounted = 0;
1992 dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
1994 if(!dev->dev_list.next)
1995 YINIT_LIST_HEAD(&dev->dev_list);
1997 ylist_add(&dev->dev_list,&yaffsfs_deviceList);
2000 void yaffs_remove_device(yaffs_dev_t *dev)
2002 ylist_del_init(&dev->dev_list);
2008 /* Directory search stuff. */
2011 * Directory search context
2013 * NB this is an opaque structure.
2020 yaffs_dirent de; /* directory entry being used by this dsc */
2021 YCHAR name[NAME_MAX+1]; /* name of directory being searched */
2022 yaffs_obj_t *dirObj; /* ptr to directory being searched */
2023 yaffs_obj_t *nextReturn; /* obj to be returned by next readddir */
2025 struct ylist_head others;
2026 } yaffsfs_DirectorySearchContext;
2030 static struct ylist_head search_contexts;
2033 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
2037 dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2041 if( ylist_empty(&dsc->dirObj->variant.dir_variant.children))
2042 dsc->nextReturn = NULL;
2044 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.dir_variant.children.next,
2045 yaffs_obj_t,siblings);
2047 /* Hey someone isn't playing nice! */
2051 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
2055 dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2057 if( dsc->nextReturn == NULL ||
2058 ylist_empty(&dsc->dirObj->variant.dir_variant.children))
2059 dsc->nextReturn = NULL;
2061 struct ylist_head *next = dsc->nextReturn->siblings.next;
2063 if( next == &dsc->dirObj->variant.dir_variant.children)
2064 dsc->nextReturn = NULL; /* end of list */
2066 dsc->nextReturn = ylist_entry(next,yaffs_obj_t,siblings);
2069 /* Hey someone isn't playing nice! */
2073 static void yaffsfs_RemoveObjectCallback(yaffs_obj_t *obj)
2076 struct ylist_head *i;
2077 yaffsfs_DirectorySearchContext *dsc;
2079 /* if search contexts not initilised then skip */
2080 if(!search_contexts.next)
2083 /* Iterate through the directory search contexts.
2084 * If any are the one being removed, then advance the dsc to
2085 * the next one to prevent a hanging ptr.
2087 ylist_for_each(i, &search_contexts) {
2089 dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
2090 if(dsc->nextReturn == obj)
2091 yaffsfs_DirAdvance(dsc);
2097 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
2099 yaffs_DIR *dir = NULL;
2100 yaffs_obj_t *obj = NULL;
2101 yaffsfs_DirectorySearchContext *dsc = NULL;
2105 obj = yaffsfs_FindObject(NULL,dirname,0,1);
2107 if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2109 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
2110 dir = (yaffs_DIR *)dsc;
2113 memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
2114 dsc->magic = YAFFS_MAGIC;
2116 yaffs_strncpy(dsc->name,dirname,NAME_MAX);
2117 YINIT_LIST_HEAD(&dsc->others);
2119 if(!search_contexts.next)
2120 YINIT_LIST_HEAD(&search_contexts);
2122 ylist_add(&dsc->others,&search_contexts);
2123 yaffsfs_SetDirRewound(dsc);
2133 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2135 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2136 struct yaffs_dirent *retVal = NULL;
2140 if(dsc && dsc->magic == YAFFS_MAGIC){
2141 yaffsfs_SetError(0);
2142 if(dsc->nextReturn){
2143 dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
2144 dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2145 dsc->de.d_off = dsc->offset++;
2146 yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2147 if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2149 /* this should not happen! */
2150 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2152 dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2154 yaffsfs_DirAdvance(dsc);
2158 yaffsfs_SetError(-EBADF);
2167 void yaffs_rewinddir(yaffs_DIR *dirp)
2169 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2173 yaffsfs_SetDirRewound(dsc);
2179 int yaffs_closedir(yaffs_DIR *dirp)
2181 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2185 ylist_del(&dsc->others); /* unhook from list */
2191 /* End of directory stuff */
2194 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2196 yaffs_obj_t *parent = NULL;
2200 int mode = 0; /* ignore for now */
2203 parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
2204 if(parent && parent->my_dev->read_only)
2205 yaffsfs_SetError(-EINVAL);
2207 obj = yaffs_create_symlink(parent,name,mode,0,0,oldpath);
2211 yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
2215 yaffsfs_SetError(-EINVAL);
2225 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
2227 yaffs_obj_t *obj = NULL;
2233 obj = yaffsfs_FindObject(NULL,path,0,1);
2236 yaffsfs_SetError(-ENOENT);
2238 } else if(obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK) {
2239 yaffsfs_SetError(-EINVAL);
2242 YCHAR *alias = obj->variant.symlink_variant.alias;
2243 memset(buf,0,bufsiz);
2244 yaffs_strncpy(buf,alias,bufsiz - 1);
2251 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
2253 /* Creates a link called newpath to existing oldpath */
2254 yaffs_obj_t *obj = NULL;
2255 yaffs_obj_t *target = NULL;
2257 int new_nameLength = 0;
2262 obj = yaffsfs_FindObject(NULL,oldpath,0,1);
2263 target = yaffsfs_FindObject(NULL,newpath,0,0);
2266 yaffsfs_SetError(-ENOENT);
2268 } else if(obj->my_dev->read_only){
2269 yaffsfs_SetError(-EINVAL);
2272 yaffsfs_SetError(-EEXIST);
2275 yaffs_obj_t *newdir = NULL;
2276 yaffs_obj_t *link = NULL;
2280 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
2283 yaffsfs_SetError(-ENOTDIR);
2285 }else if(newdir->my_dev != obj->my_dev){
2286 yaffsfs_SetError(-EXDEV);
2290 new_nameLength = yaffs_strnlen(newname,YAFFS_MAX_NAME_LENGTH+1);
2292 if(new_nameLength == 0){
2293 yaffsfs_SetError(-ENOENT);
2295 } else if (new_nameLength > YAFFS_MAX_NAME_LENGTH){
2296 yaffsfs_SetError(-ENAMETOOLONG);
2301 link = yaffs_link_obj(newdir,newname,obj);
2305 yaffsfs_SetError(-ENOSPC);
2316 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
2325 * Returns number of handles attached to the object
2327 int yaffs_n_handles(const YCHAR *path)
2331 obj = yaffsfs_FindObject(NULL,path,0,1);
2333 return yaffsfs_CountHandles(obj);
2336 int yaffs_get_error(void)
2338 return yaffsfs_GetLastError();
2341 int yaffs_dump_dev(const YCHAR *path)
2346 yaffs_obj_t *obj = yaffsfs_FindRoot(path,&rest);
2349 yaffs_dev_t *dev = obj->my_dev;
2352 "n_page_writes.......... %d\n"
2353 "n_page_reads........... %d\n"
2354 "n_erasures....... %d\n"
2355 "n_gc_copies............ %d\n"
2356 "garbageCollections... %d\n"
2357 "passiveGarbageColl'ns %d\n"
2363 dev->garbageCollections,
2364 dev->passiveGarbageCollections