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(!obj ? -ENOSPC : -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);
1065 if(whence == SEEK_SET){
1068 } else if(whence == SEEK_CUR) {
1069 if( (h->position + offset) >= 0)
1070 pos = (h->position + offset);
1071 } else if(whence == SEEK_END) {
1072 fSize = yaffs_get_obj_length(obj);
1073 if(fSize >= 0 && (fSize + offset) >= 0)
1074 pos = fSize + offset;
1080 yaffsfs_SetError(-EINVAL);
1089 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
1091 yaffs_obj_t *dir = NULL;
1092 yaffs_obj_t *obj = NULL;
1094 int result = YAFFS_FAIL;
1098 obj = yaffsfs_FindObject(NULL,path,0,0);
1099 dir = yaffsfs_FindDirectory(NULL,path,&name,0);
1101 yaffsfs_SetError(-ENOTDIR);
1103 yaffsfs_SetError(-ENOENT);
1104 else if(obj->my_dev->read_only)
1105 yaffsfs_SetError(-EINVAL);
1106 else if(!isDirectory && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1107 yaffsfs_SetError(-EISDIR);
1108 else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1109 yaffsfs_SetError(-ENOTDIR);
1111 result = yaffs_unlinker(dir,name);
1113 if(result == YAFFS_FAIL && isDirectory)
1114 yaffsfs_SetError(-ENOTEMPTY);
1121 return (result == YAFFS_FAIL) ? -1 : 0;
1125 int yaffs_rmdir(const YCHAR *path)
1127 return yaffsfs_DoUnlink(path,1);
1130 int yaffs_unlink(const YCHAR *path)
1132 return yaffsfs_DoUnlink(path,0);
1135 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1137 yaffs_obj_t *olddir = NULL;
1138 yaffs_obj_t *newdir = NULL;
1139 yaffs_obj_t *obj = NULL;
1142 int result= YAFFS_FAIL;
1143 int rename_allowed = 1;
1147 olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1148 newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1149 obj = yaffsfs_FindObject(NULL,oldPath,0,0);
1151 if(!olddir || !newdir || !obj) {
1153 yaffsfs_SetError(-EBADF);
1155 } else if(obj->my_dev->read_only){
1156 yaffsfs_SetError(-EINVAL);
1158 } else if(olddir->my_dev != newdir->my_dev) {
1159 /* oops must be on same device */
1161 yaffsfs_SetError(-EXDEV);
1163 } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1165 * It is a directory, check that it is not being renamed to
1166 * being its own decendent.
1167 * Do this by tracing from the new directory back to the root, checking for obj
1170 yaffs_obj_t *xx = newdir;
1172 while( rename_allowed && xx){
1178 yaffsfs_SetError(-EACCES);
1182 result = yaffs_rename_obj(olddir,oldname,newdir,newname);
1186 return (result == YAFFS_FAIL) ? -1 : 0;
1190 static int yaffsfs_DoStat(yaffs_obj_t *obj,struct yaffs_stat *buf)
1194 obj = yaffs_get_equivalent_obj(obj);
1197 buf->st_dev = (int)obj->my_dev->os_context;
1198 buf->st_ino = obj->obj_id;
1199 buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
1201 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1202 buf->st_mode |= S_IFDIR;
1203 else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1204 buf->st_mode |= S_IFLNK;
1205 else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1206 buf->st_mode |= S_IFREG;
1208 buf->st_nlink = yaffs_get_obj_link_count(obj);
1211 buf->st_rdev = obj->yst_rdev;
1212 buf->st_size = yaffs_get_obj_length(obj);
1213 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
1214 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1215 #if CONFIG_YAFFS_WINCE
1216 buf->yst_wince_atime[0] = obj->win_atime[0];
1217 buf->yst_wince_atime[1] = obj->win_atime[1];
1218 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1219 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1220 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1221 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1223 buf->yst_atime = obj->yst_atime;
1224 buf->yst_ctime = obj->yst_ctime;
1225 buf->yst_mtime = obj->yst_mtime;
1232 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1240 obj = yaffsfs_FindObject(NULL,path,0,1);
1243 obj = yaffsfs_FollowLink(obj,0);
1246 retVal = yaffsfs_DoStat(obj,buf);
1248 /* todo error not found */
1249 yaffsfs_SetError(-ENOENT);
1257 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1259 return yaffsfs_DoStatOrLStat(path,buf,0);
1262 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1264 return yaffsfs_DoStatOrLStat(path,buf,1);
1267 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1274 obj = yaffsfs_GetHandleObject(fd);
1277 retVal = yaffsfs_DoStat(obj,buf);
1280 yaffsfs_SetError(-EBADF);
1287 #ifndef CONFIG_YAFFS_WINCE
1288 /* xattrib functions */
1291 static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags, int follow)
1299 obj = yaffsfs_FindObject(NULL,path,0,1);
1302 obj = yaffsfs_FollowLink(obj,0);
1305 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1307 yaffsfs_SetError(retVal);
1311 /* todo error not found */
1312 yaffsfs_SetError(-ENOENT);
1320 int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1322 return yaffs_do_setxattr(path, name, data, size, flags, 1);
1325 int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1327 return yaffs_do_setxattr(path, name, data, size, flags, 0);
1332 int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
1339 obj = yaffsfs_GetHandleObject(fd);
1342 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1344 yaffsfs_SetError(retVal);
1349 yaffsfs_SetError(-EBADF);
1356 static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
1364 obj = yaffsfs_FindObject(NULL,path,0,1);
1367 obj = yaffsfs_FollowLink(obj,0);
1370 retVal = yaffs_get_xattrib(obj,name,data,size);
1372 yaffsfs_SetError(retVal);
1376 /* todo error not found */
1377 yaffsfs_SetError(-ENOENT);
1385 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1387 return yaffs_do_getxattr( path, name, data, size, 1);
1389 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1391 return yaffs_do_getxattr( path, name, data, size, 0);
1396 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1403 obj = yaffsfs_GetHandleObject(fd);
1406 retVal = yaffs_get_xattrib(obj,name,data,size);
1408 yaffsfs_SetError(retVal);
1413 yaffsfs_SetError(-EBADF);
1420 static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
1428 obj = yaffsfs_FindObject(NULL,path,0,1);
1431 obj = yaffsfs_FollowLink(obj,0);
1434 retVal = yaffs_list_xattrib(obj, data,size);
1436 yaffsfs_SetError(retVal);
1440 /* todo error not found */
1441 yaffsfs_SetError(-ENOENT);
1449 int yaffs_listxattr(const YCHAR *path, char *data, int size)
1451 return yaffs_do_listxattr(path, data, size, 1);
1454 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
1456 return yaffs_do_listxattr(path, data, size, 0);
1459 int yaffs_flistxattr(int fd, char *data, int size)
1466 obj = yaffsfs_GetHandleObject(fd);
1469 retVal = yaffs_list_xattrib(obj,data,size);
1471 yaffsfs_SetError(retVal);
1476 yaffsfs_SetError(-EBADF);
1483 static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
1491 obj = yaffsfs_FindObject(NULL,path,0,1);
1494 obj = yaffsfs_FollowLink(obj,0);
1497 retVal = yaffs_remove_xattrib(obj,name);
1499 yaffsfs_SetError(retVal);
1503 /* todo error not found */
1504 yaffsfs_SetError(-ENOENT);
1512 int yaffs_removexattr(const YCHAR *path, const char *name)
1514 return yaffs_do_removexattr(path, name, 1);
1517 int yaffs_lremovexattr(const YCHAR *path, const char *name)
1519 return yaffs_do_removexattr(path, name, 0);
1522 int yaffs_fremovexattr(int fd, const char *name)
1529 obj = yaffsfs_GetHandleObject(fd);
1532 retVal = yaffs_remove_xattrib(obj,name);
1534 yaffsfs_SetError(retVal);
1539 yaffsfs_SetError(-EBADF);
1547 #ifdef CONFIG_YAFFS_WINCE
1548 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1555 obj = yaffsfs_GetHandleObject(fd);
1560 wctime[0] = obj->win_ctime[0];
1561 wctime[1] = obj->win_ctime[1];
1564 watime[0] = obj->win_atime[0];
1565 watime[1] = obj->win_atime[1];
1568 wmtime[0] = obj->win_mtime[0];
1569 wmtime[1] = obj->win_mtime[1];
1576 yaffsfs_SetError(-EBADF);
1584 int yaffs_set_wince_times(int fd,
1585 const unsigned *wctime,
1586 const unsigned *watime,
1587 const unsigned *wmtime)
1594 obj = yaffsfs_GetHandleObject(fd);
1599 obj->win_ctime[0] = wctime[0];
1600 obj->win_ctime[1] = wctime[1];
1603 obj->win_atime[0] = watime[0];
1604 obj->win_atime[1] = watime[1];
1607 obj->win_mtime[0] = wmtime[0];
1608 obj->win_mtime[1] = wmtime[1];
1612 result = yaffs_flush_file(obj,0,0);
1616 yaffsfs_SetError(-EBADF);
1626 static int yaffsfs_DoChMod(yaffs_obj_t *obj,mode_t mode)
1631 obj = yaffs_get_equivalent_obj(obj);
1634 obj->yst_mode = mode;
1636 result = yaffs_flush_file(obj,0,0);
1639 return result == YAFFS_OK ? 0 : -1;
1643 int yaffs_access(const YCHAR *path, int amode)
1651 obj = yaffsfs_FindObject(NULL,path,0,1);
1656 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1658 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1660 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1664 yaffsfs_SetError(-EACCES);
1668 /* todo error not found */
1669 yaffsfs_SetError(-ENOENT);
1680 int yaffs_chmod(const YCHAR *path, mode_t mode)
1688 obj = yaffsfs_FindObject(NULL,path,0,1);
1691 yaffsfs_SetError(-ENOENT);
1692 else if(obj->my_dev->read_only)
1693 yaffsfs_SetError(-EINVAL);
1695 retVal = yaffsfs_DoChMod(obj,mode);
1704 int yaffs_fchmod(int fd, mode_t mode)
1711 obj = yaffsfs_GetHandleObject(fd);
1714 yaffsfs_SetError(-ENOENT);
1715 else if(obj->my_dev->read_only)
1716 yaffsfs_SetError(-EINVAL);
1718 retVal = yaffsfs_DoChMod(obj,mode);
1726 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1728 yaffs_obj_t *parent = NULL;
1729 yaffs_obj_t *dir = NULL;
1731 YCHAR *use_path = NULL;
1732 int path_length = 0;
1738 * We don't have a definition for max path length.
1739 * We will use 3 * max name length instead.
1742 path_length = strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1);
1744 /* If the last character is a path divider, then we need to
1745 * trim it back so that the name look-up works properly.
1746 * eg. /foo/new_dir/ -> /foo/newdir
1747 * Curveball: Need to handle multiple path dividers:
1748 * eg. /foof/sdfse///// -> /foo/sdfse
1750 if(path_length > 0 &&
1751 yaffsfs_IsPathDivider(path[path_length-1])){
1752 use_path = YMALLOC(path_length + 1);
1754 yaffsfs_SetError(-ENOMEM);
1757 strcpy(use_path, path);
1758 for(i = path_length-1;
1759 i >= 0 && yaffsfs_IsPathDivider(use_path[i]);
1761 use_path[i] = (YCHAR) 0;
1766 parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1767 if(parent && yaffs_strnlen(name,5) == 0){
1768 /* Trying to make the root itself */
1769 yaffsfs_SetError(-EEXIST);
1770 } else if(parent && parent->my_dev->read_only){
1771 yaffsfs_SetError(-EINVAL);
1774 dir = yaffs_create_dir(parent,name,mode,0,0);
1779 yaffsfs_SetError(-ENOENT); /* missing path */
1780 else if (yaffs_find_by_name(parent,name))
1781 yaffsfs_SetError(-EEXIST); /* the name already exists */
1783 yaffsfs_SetError(-ENOSPC); /* just assume no space */
1796 void * yaffs_getdev(const YCHAR *path)
1798 yaffs_dev_t *dev=NULL;
1800 dev = yaffsfs_FindDevice(path,&dummy);
1804 int yaffs_mount2(const YCHAR *path,int read_only)
1807 int result=YAFFS_FAIL;
1808 yaffs_dev_t *dev=NULL;
1811 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1815 yaffsfs_InitHandles();
1817 dev = yaffsfs_FindDevice(path,&dummy);
1819 if(!dev->is_mounted){
1820 dev->read_only = read_only ? 1 : 0;
1821 result = yaffs_guts_initialise(dev);
1822 if(result == YAFFS_FAIL)
1823 /* todo error - mount failed */
1824 yaffsfs_SetError(-ENOMEM);
1825 retVal = result ? 0 : -1;
1829 /* todo error - already mounted. */
1830 yaffsfs_SetError(-EBUSY);
1832 /* todo error - no device */
1833 yaffsfs_SetError(-ENODEV);
1840 int yaffs_mount(const YCHAR *path)
1842 return yaffs_mount2(path,0);
1845 int yaffs_sync(const YCHAR *path)
1848 yaffs_dev_t *dev=NULL;
1852 dev = yaffsfs_FindDevice(path,&dummy);
1854 if(dev->is_mounted){
1856 yaffs_flush_whole_cache(dev);
1857 yaffs_checkpoint_save(dev);
1861 /* todo error - not mounted. */
1862 yaffsfs_SetError(-EINVAL);
1865 /* todo error - no device */
1866 yaffsfs_SetError(-ENODEV);
1873 int yaffs_remount(const YCHAR *path, int force, int read_only)
1876 yaffs_dev_t *dev=NULL;
1880 dev = yaffsfs_FindDevice(path,&dummy);
1882 if(dev->is_mounted){
1886 yaffs_flush_whole_cache(dev);
1888 for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
1889 if(yaffsfs_handle[i].useCount>0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->my_dev == dev)
1890 inUse = 1; /* the device is in use, can't unmount */
1893 if(!inUse || force){
1895 yaffs_checkpoint_save(dev);
1896 dev->read_only = read_only ? 1 : 0;
1899 yaffsfs_SetError(-EBUSY);
1902 yaffsfs_SetError(-EINVAL);
1906 yaffsfs_SetError(-ENODEV);
1913 int yaffs_unmount2(const YCHAR *path, int force)
1916 yaffs_dev_t *dev=NULL;
1920 dev = yaffsfs_FindDevice(path,&dummy);
1922 if(dev->is_mounted){
1926 yaffs_flush_whole_cache(dev);
1927 yaffs_checkpoint_save(dev);
1929 for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
1930 if(yaffsfs_handle[i].useCount > 0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->my_dev == dev)
1931 inUse = 1; /* the device is in use, can't unmount */
1934 if(!inUse || force){
1935 yaffs_deinitialise(dev);
1939 /* todo error can't unmount as files are open */
1940 yaffsfs_SetError(-EBUSY);
1943 /* todo error - not mounted. */
1944 yaffsfs_SetError(-EINVAL);
1948 /* todo error - no device */
1949 yaffsfs_SetError(-ENODEV);
1956 int yaffs_unmount(const YCHAR *path)
1958 return yaffs_unmount2(path,0);
1961 loff_t yaffs_freespace(const YCHAR *path)
1964 yaffs_dev_t *dev=NULL;
1968 dev = yaffsfs_FindDevice(path,&dummy);
1969 if(dev && dev->is_mounted){
1970 retVal = yaffs_get_n_free_chunks(dev);
1971 retVal *= dev->data_bytes_per_chunk;
1974 yaffsfs_SetError(-EINVAL);
1980 loff_t yaffs_totalspace(const YCHAR *path)
1983 yaffs_dev_t *dev=NULL;
1987 dev = yaffsfs_FindDevice(path,&dummy);
1988 if(dev && dev->is_mounted){
1989 retVal = (dev->param.end_block - dev->param.start_block + 1) - dev->param.n_reserved_blocks;
1990 retVal *= dev->param.chunks_per_block;
1991 retVal *= dev->data_bytes_per_chunk;
1994 yaffsfs_SetError(-EINVAL);
2000 int yaffs_inodecount(const YCHAR *path)
2003 yaffs_dev_t *dev=NULL;
2007 dev = yaffsfs_FindDevice(path,&dummy);
2008 if(dev && dev->is_mounted) {
2009 int n_obj = dev->n_obj;
2010 if(n_obj > dev->n_hardlinks)
2011 retVal = n_obj - dev->n_hardlinks;
2015 yaffsfs_SetError(-EINVAL);
2022 void yaffs_add_device(yaffs_dev_t *dev)
2024 dev->is_mounted = 0;
2025 dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
2027 if(!dev->dev_list.next)
2028 YINIT_LIST_HEAD(&dev->dev_list);
2030 ylist_add(&dev->dev_list,&yaffsfs_deviceList);
2033 void yaffs_remove_device(yaffs_dev_t *dev)
2035 ylist_del_init(&dev->dev_list);
2041 /* Directory search stuff. */
2044 * Directory search context
2046 * NB this is an opaque structure.
2053 yaffs_dirent de; /* directory entry being used by this dsc */
2054 YCHAR name[NAME_MAX+1]; /* name of directory being searched */
2055 yaffs_obj_t *dirObj; /* ptr to directory being searched */
2056 yaffs_obj_t *nextReturn; /* obj to be returned by next readddir */
2058 struct ylist_head others;
2059 } yaffsfs_DirectorySearchContext;
2063 static struct ylist_head search_contexts;
2066 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
2070 dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2074 if( ylist_empty(&dsc->dirObj->variant.dir_variant.children))
2075 dsc->nextReturn = NULL;
2077 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.dir_variant.children.next,
2078 yaffs_obj_t,siblings);
2080 /* Hey someone isn't playing nice! */
2084 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
2088 dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2090 if( dsc->nextReturn == NULL ||
2091 ylist_empty(&dsc->dirObj->variant.dir_variant.children))
2092 dsc->nextReturn = NULL;
2094 struct ylist_head *next = dsc->nextReturn->siblings.next;
2096 if( next == &dsc->dirObj->variant.dir_variant.children)
2097 dsc->nextReturn = NULL; /* end of list */
2099 dsc->nextReturn = ylist_entry(next,yaffs_obj_t,siblings);
2102 /* Hey someone isn't playing nice! */
2106 static void yaffsfs_RemoveObjectCallback(yaffs_obj_t *obj)
2109 struct ylist_head *i;
2110 yaffsfs_DirectorySearchContext *dsc;
2112 /* if search contexts not initilised then skip */
2113 if(!search_contexts.next)
2116 /* Iterate through the directory search contexts.
2117 * If any are the one being removed, then advance the dsc to
2118 * the next one to prevent a hanging ptr.
2120 ylist_for_each(i, &search_contexts) {
2122 dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
2123 if(dsc->nextReturn == obj)
2124 yaffsfs_DirAdvance(dsc);
2130 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
2132 yaffs_DIR *dir = NULL;
2133 yaffs_obj_t *obj = NULL;
2134 yaffsfs_DirectorySearchContext *dsc = NULL;
2138 obj = yaffsfs_FindObject(NULL,dirname,0,1);
2140 if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2142 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
2143 dir = (yaffs_DIR *)dsc;
2146 memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
2147 dsc->magic = YAFFS_MAGIC;
2149 yaffs_strncpy(dsc->name,dirname,NAME_MAX);
2150 YINIT_LIST_HEAD(&dsc->others);
2152 if(!search_contexts.next)
2153 YINIT_LIST_HEAD(&search_contexts);
2155 ylist_add(&dsc->others,&search_contexts);
2156 yaffsfs_SetDirRewound(dsc);
2166 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2168 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2169 struct yaffs_dirent *retVal = NULL;
2173 if(dsc && dsc->magic == YAFFS_MAGIC){
2174 yaffsfs_SetError(0);
2175 if(dsc->nextReturn){
2176 dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
2177 dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2178 dsc->de.d_off = dsc->offset++;
2179 yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2180 if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2182 /* this should not happen! */
2183 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2185 dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2187 yaffsfs_DirAdvance(dsc);
2191 yaffsfs_SetError(-EBADF);
2200 void yaffs_rewinddir(yaffs_DIR *dirp)
2202 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2206 yaffsfs_SetDirRewound(dsc);
2212 int yaffs_closedir(yaffs_DIR *dirp)
2214 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2218 ylist_del(&dsc->others); /* unhook from list */
2224 /* End of directory stuff */
2227 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2229 yaffs_obj_t *parent = NULL;
2233 int mode = 0; /* ignore for now */
2236 parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
2237 if(parent && parent->my_dev->read_only)
2238 yaffsfs_SetError(-EINVAL);
2240 obj = yaffs_create_symlink(parent,name,mode,0,0,oldpath);
2244 yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
2248 yaffsfs_SetError(-EINVAL);
2258 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
2260 yaffs_obj_t *obj = NULL;
2266 obj = yaffsfs_FindObject(NULL,path,0,1);
2269 yaffsfs_SetError(-ENOENT);
2271 } else if(obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK) {
2272 yaffsfs_SetError(-EINVAL);
2275 YCHAR *alias = obj->variant.symlink_variant.alias;
2276 memset(buf,0,bufsiz);
2277 yaffs_strncpy(buf,alias,bufsiz - 1);
2284 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
2286 /* Creates a link called newpath to existing oldpath */
2287 yaffs_obj_t *obj = NULL;
2288 yaffs_obj_t *target = NULL;
2290 int new_nameLength = 0;
2295 obj = yaffsfs_FindObject(NULL,oldpath,0,1);
2296 target = yaffsfs_FindObject(NULL,newpath,0,0);
2299 yaffsfs_SetError(-ENOENT);
2301 } else if(obj->my_dev->read_only){
2302 yaffsfs_SetError(-EINVAL);
2305 yaffsfs_SetError(-EEXIST);
2308 yaffs_obj_t *newdir = NULL;
2309 yaffs_obj_t *link = NULL;
2313 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
2316 yaffsfs_SetError(-ENOTDIR);
2318 }else if(newdir->my_dev != obj->my_dev){
2319 yaffsfs_SetError(-EXDEV);
2323 new_nameLength = yaffs_strnlen(newname,YAFFS_MAX_NAME_LENGTH+1);
2325 if(new_nameLength == 0){
2326 yaffsfs_SetError(-ENOENT);
2328 } else if (new_nameLength > YAFFS_MAX_NAME_LENGTH){
2329 yaffsfs_SetError(-ENAMETOOLONG);
2334 link = yaffs_link_obj(newdir,newname,obj);
2338 yaffsfs_SetError(-ENOSPC);
2349 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
2358 * Returns number of handles attached to the object
2360 int yaffs_n_handles(const YCHAR *path)
2364 obj = yaffsfs_FindObject(NULL,path,0,1);
2366 return yaffsfs_CountHandles(obj);
2369 int yaffs_get_error(void)
2371 return yaffsfs_GetLastError();
2374 int yaffs_dump_dev(const YCHAR *path)
2379 yaffs_obj_t *obj = yaffsfs_FindRoot(path,&rest);
2382 yaffs_dev_t *dev = obj->my_dev;
2385 "n_page_writes.......... %d\n"
2386 "n_page_reads........... %d\n"
2387 "n_erasures....... %d\n"
2388 "n_gc_copies............ %d\n"
2389 "garbageCollections... %d\n"
2390 "passiveGarbageColl'ns %d\n"
2396 dev->garbageCollections,
2397 dev->passiveGarbageCollections