From 2e51ed27a28a076ee9eb870ba8c0eb09b8114b01 Mon Sep 17 00:00:00 2001 From: charles Date: Wed, 3 Nov 2004 08:29:28 +0000 Subject: [PATCH] *** empty log message *** --- direct/Makefile | 45 ++ direct/dtest.c | 1334 +++++++++++++++++++++++++++++++++++ direct/yaffs_fileem.c | 217 ++++++ direct/yaffs_fileem2k.c | 307 ++++++++ direct/yaffs_fileem2k.h | 45 ++ direct/yaffs_flashif.c | 233 ++++++ direct/yaffs_flashif.h | 35 + direct/yaffs_packedtags.c | 42 ++ direct/yaffs_packedtags.h | 24 + direct/yaffs_ramdisk.c | 232 ++++++ direct/yaffs_ramdisk.h | 32 + direct/yaffscfg.c | 122 ++++ direct/yaffscfg.h | 30 + direct/yaffscfg2k.c | 137 ++++ direct/yaffsfs.c | 1412 +++++++++++++++++++++++++++++++++++++ direct/yaffsfs.h | 216 ++++++ 16 files changed, 4463 insertions(+) create mode 100644 direct/Makefile create mode 100644 direct/dtest.c create mode 100644 direct/yaffs_fileem.c create mode 100644 direct/yaffs_fileem2k.c create mode 100644 direct/yaffs_fileem2k.h create mode 100644 direct/yaffs_flashif.c create mode 100644 direct/yaffs_flashif.h create mode 100644 direct/yaffs_packedtags.c create mode 100644 direct/yaffs_packedtags.h create mode 100644 direct/yaffs_ramdisk.c create mode 100644 direct/yaffs_ramdisk.h create mode 100644 direct/yaffscfg.c create mode 100644 direct/yaffscfg.h create mode 100644 direct/yaffscfg2k.c create mode 100644 direct/yaffsfs.c create mode 100644 direct/yaffsfs.h diff --git a/direct/Makefile b/direct/Makefile new file mode 100644 index 0000000..1033e04 --- /dev/null +++ b/direct/Makefile @@ -0,0 +1,45 @@ +# Makefile for YAFFS direct test +# +# Copyright (C) 2003 Aleph One Ltd. +# +# Created by Charles Manning +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# NB Warning this Makefile does not include header dependencies. +# +# $Id: Makefile,v 1.1 2004-11-03 08:29:28 charles Exp $ + +CFLAGS = -Wall -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DYAFFS2_DEFINES -g +#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations +#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline + + +DIRECTTESTOBJS = dtest.o yaffs_ecc.o yaffscfg.o yaffsfs.o yaffs_ramdisk.o yaffs_guts.o yaffs_fileem.o yaffs_packedtags.o yaffs_tagscompat.o + +BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o + +ALLOBJS = dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o bootldtst.o yboot.o + +SYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h + +all: directtest boottest + +$(ALLOBJS): %.o: %.c + gcc -c $(CFLAGS) $< -o $@ + +$(SYMLINKS): + ln -s ../$@ $@ + +directtest: $(SYMLINKS) $(DIRECTTESTOBJS) + gcc -o $@ $(DIRECTTESTOBJS) + + +boottest: $(SYMLINKS) $(BOOTTESTOBJS) + gcc -o $@ $(BOOTTESTOBJS) + + +clean: + rm -f $(ALLOBJS) core diff --git a/direct/dtest.c b/direct/dtest.c new file mode 100644 index 0000000..90814f7 --- /dev/null +++ b/direct/dtest.c @@ -0,0 +1,1334 @@ +/* +* Test code for the "direct" interface. +*/ + + +#include +#include +#include +#include + +#include "yaffsfs.h" + +void dumpDir(const char *dname); + +char xx[600]; + +void copy_in_a_file(char *yaffsName,char *inName) +{ + int inh,outh; + unsigned char buffer[100]; + int ni,no; + inh = open(inName,O_RDONLY); + outh = yaffs_open(yaffsName, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + while((ni = read(inh,buffer,100)) > 0) + { + no = yaffs_write(outh,buffer,ni); + if(ni != no) + { + printf("problem writing yaffs file\n"); + } + + } + + yaffs_close(outh); + close(inh); +} + +void make_a_file(char *yaffsName,char bval,int sizeOfFile) +{ + int outh; + int i; + unsigned char buffer[100]; + + outh = yaffs_open(yaffsName, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + memset(buffer,bval,100); + + do{ + i = sizeOfFile; + if(i > 100) i = 100; + sizeOfFile -= i; + + yaffs_write(outh,buffer,i); + + } while (sizeOfFile > 0); + + + yaffs_close(outh); + +} + +void make_pattern_file(char *fn,int size) +{ + int outh; + int marker; + int i; + outh = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + yaffs_lseek(outh,size-1,SEEK_SET); + yaffs_write(outh,"A",1); + + for(i = 0; i < size; i+=256) + { + marker = ~i; + yaffs_lseek(outh,i,SEEK_SET); + yaffs_write(outh,&marker,sizeof(marker)); + } + yaffs_close(outh); + +} + +int check_pattern_file(char *fn) +{ + int h; + int marker; + int i; + int size; + int ok = 1; + + h = yaffs_open(fn, O_RDWR,0); + size = yaffs_lseek(h,0,SEEK_END); + + for(i = 0; i < size && ok; i+=256) + { + yaffs_lseek(h,i,SEEK_SET); + yaffs_read(h,&marker,sizeof(marker)); + ok = (marker == ~i); + if(!ok) + { + printf("pattern check failed on file %s, size %d at position %d. Got %x instead of %x\n", + fn,size,i,marker,~i); + } + } + yaffs_close(h); + return ok; +} + + + +void dump_file(const char *fn) +{ + int i; + int size; + int h; + + h = yaffs_open(fn,O_RDONLY,0); + if(h < 0) + { + printf("*****\nDump file %s does not exist\n",fn); + } + else + { + size = yaffs_lseek(h,0,SEEK_SET); + printf("*****\nDump file %s size %d\n",fn,size); + for(i = 0; i < size; i++) + { + + } + } +} + +void short_scan_test(const char *path, int fsize, int niterations) +{ + int i; + char fn[100]; + + sprintf(fn,"%s/%s",path,"f1"); + + yaffs_StartUp(); + for(i = 0; i < niterations; i++) + { + printf("\n*****************\nIteration %d\n",i); + yaffs_mount(path); + printf("\nmount: Directory look-up of %s\n",path); + dumpDir(path); + make_a_file(fn,1,fsize); + yaffs_unmount(path); + } +} + +void scan_pattern_test(const char *path, int fsize, int niterations) +{ + int i; + int j; + char fn[3][100]; + int result; + + sprintf(fn[0],"%s/%s",path,"f0"); + sprintf(fn[1],"%s/%s",path,"f1"); + sprintf(fn[2],"%s/%s",path,"f2"); + + yaffs_StartUp(); + + for(i = 0; i < niterations; i++) + { + printf("\n*****************\nIteration %d\n",i); + yaffs_mount(path); + printf("\nmount: Directory look-up of %s\n",path); + dumpDir(path); + for(j = 0; j < 3; j++) + { + result = check_pattern_file(fn[j]); + make_pattern_file(fn[j],fsize); + result = check_pattern_file(fn[j]); + } + yaffs_unmount(path); + } +} + +void fill_disk(char *path,int nfiles) +{ + int h; + int n; + int result; + int f; + + char str[50]; + + for(n = 0; n < nfiles; n++) + { + sprintf(str,"%s/%d",path,n); + + h = yaffs_open(str, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + printf("writing file %s handle %d ",str, h); + + while ((result = yaffs_write(h,xx,600)) == 600) + { + f = yaffs_freespace("/boot"); + } + result = yaffs_close(h); + printf(" close %d\n",result); + } +} + +void fill_disk_and_delete(char *path, int nfiles, int ncycles) +{ + int i,j; + char str[50]; + int result; + + for(i = 0; i < ncycles; i++) + { + printf("@@@@@@@@@@@@@@ cycle %d\n",i); + fill_disk(path,nfiles); + + for(j = 0; j < nfiles; j++) + { + sprintf(str,"%s/%d",path,j); + result = yaffs_unlink(str); + printf("unlinking file %s, result %d\n",str,result); + } + } +} + + +void fill_files(char *path,int flags, int maxIterations,int siz) +{ + int i; + int j; + char str[50]; + int h; + + i = 0; + + do{ + sprintf(str,"%s/%d",path,i); + h = yaffs_open(str, O_CREAT | O_TRUNC | O_RDWR,S_IREAD | S_IWRITE); + yaffs_close(h); + + if(h >= 0) + { + for(j = 0; j < siz; j++) + { + yaffs_write(h,str,1); + } + } + + if( flags & 1) + { + yaffs_unlink(str); + } + i++; + } while(h >= 0 && i < maxIterations); + + if(flags & 2) + { + i = 0; + do{ + sprintf(str,"%s/%d",path,i); + printf("unlink %s\n",str); + i++; + } while(yaffs_unlink(str) >= 0); + } +} + +void leave_unlinked_file(char *path,int maxIterations,int siz) +{ + int i; + char str[50]; + int h; + + i = 0; + + do{ + sprintf(str,"%s/%d",path,i); + printf("create %s\n",str); + h = yaffs_open(str, O_CREAT | O_TRUNC | O_RDWR,S_IREAD | S_IWRITE); + if(h >= 0) + { + yaffs_unlink(str); + } + i++; + } while(h < 0 && i < maxIterations); + + if(h >= 0) + { + for(i = 0; i < siz; i++) + { + yaffs_write(h,str,1); + } + } + + printf("Leaving file %s open\n",str); + +} + +void dumpDirFollow(const char *dname) +{ + yaffs_DIR *d; + yaffs_dirent *de; + struct yaffs_stat s; + char str[100]; + + d = yaffs_opendir(dname); + + if(!d) + { + printf("opendir failed\n"); + } + else + { + while((de = yaffs_readdir(d)) != NULL) + { + sprintf(str,"%s/%s",dname,de->d_name); + + yaffs_stat(str,&s); + + printf("%s length %d mode %X ",de->d_name,(int)s.st_size,s.st_mode); + switch(s.st_mode & S_IFMT) + { + case S_IFREG: printf("data file"); break; + case S_IFDIR: printf("directory"); break; + case S_IFLNK: printf("symlink -->"); + if(yaffs_readlink(str,str,100) < 0) + printf("no alias"); + else + printf("\"%s\"",str); + break; + default: printf("unknown"); break; + } + + printf("\n"); + } + + yaffs_closedir(d); + } + printf("\n"); + + printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); + +} + + +void dumpDir(const char *dname) +{ + yaffs_DIR *d; + yaffs_dirent *de; + struct yaffs_stat s; + char str[100]; + + d = yaffs_opendir(dname); + + if(!d) + { + printf("opendir failed\n"); + } + else + { + while((de = yaffs_readdir(d)) != NULL) + { + sprintf(str,"%s/%s",dname,de->d_name); + + yaffs_lstat(str,&s); + + printf("%s length %d mode %X ",de->d_name,(int)s.st_size,s.st_mode); + switch(s.st_mode & S_IFMT) + { + case S_IFREG: printf("data file"); break; + case S_IFDIR: printf("directory"); break; + case S_IFLNK: printf("symlink -->"); + if(yaffs_readlink(str,str,100) < 0) + printf("no alias"); + else + printf("\"%s\"",str); + break; + default: printf("unknown"); break; + } + + printf("\n"); + } + + yaffs_closedir(d); + } + printf("\n"); + + printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); + +} + + +static void PermissionsCheck(const char *path, mode_t tmode, int tflags,int expectedResult) +{ + int fd; + + if(yaffs_chmod(path,tmode)< 0) printf("chmod failed\n"); + + fd = yaffs_open(path,tflags,0); + + if((fd >= 0) != (expectedResult > 0)) + { + printf("Permissions check %x %x %d failed\n",tmode,tflags,expectedResult); + } + else + { + printf("Permissions check %x %x %d OK\n",tmode,tflags,expectedResult); + } + + + yaffs_close(fd); + + +} + +int long_test(int argc, char *argv[]) +{ + + int f; + int r; + char buffer[20]; + + char str[100]; + + int h; + mode_t temp_mode; + struct yaffs_stat ystat; + + yaffs_StartUp(); + + yaffs_mount("/boot"); + yaffs_mount("/data"); + yaffs_mount("/flash"); + yaffs_mount("/ram"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /data\n"); + dumpDir("/data"); + printf("\nDirectory look-up of /flash\n"); + dumpDir("/flash"); + + //leave_unlinked_file("/flash",20000,0); + //leave_unlinked_file("/data",20000,0); + + leave_unlinked_file("/ram",20,0); + + + f = yaffs_open("/boot/b1", O_RDONLY,0); + + printf("open /boot/b1 readonly, f=%d\n",f); + + f = yaffs_open("/boot/b1", O_CREAT,S_IREAD | S_IWRITE); + + printf("open /boot/b1 O_CREAT, f=%d\n",f); + + + r = yaffs_write(f,"hello",1); + printf("write %d attempted to write to a read-only file\n",r); + + r = yaffs_close(f); + + printf("close %d\n",r); + + f = yaffs_open("/boot/b1", O_RDWR,0); + + printf("open /boot/b1 O_RDWR,f=%d\n",f); + + + r = yaffs_write(f,"hello",2); + printf("write %d attempted to write to a writeable file\n",r); + r = yaffs_write(f,"world",3); + printf("write %d attempted to write to a writeable file\n",r); + + r= yaffs_lseek(f,0,SEEK_END); + printf("seek end %d\n",r); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + r= yaffs_lseek(f,0,SEEK_SET); + printf("seek set %d\n",r); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + + // Check values reading at end. + // A read past end of file should return 0 for 0 bytes read. + + r= yaffs_lseek(f,0,SEEK_END); + r = yaffs_read(f,buffer,10); + printf("read at end returned %d\n",r); + r= yaffs_lseek(f,500,SEEK_END); + r = yaffs_read(f,buffer,10); + printf("read past end returned %d\n",r); + + r = yaffs_close(f); + + printf("close %d\n",r); + + copy_in_a_file("/boot/yyfile","xxx"); + + // Create a file with a long name + + copy_in_a_file("/boot/file with a long name","xxx"); + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check stat + r = yaffs_stat("/boot/file with a long name",&ystat); + + // Check rename + + r = yaffs_rename("/boot/file with a long name","/boot/r1"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check unlink + r = yaffs_unlink("/boot/r1"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check mkdir + + r = yaffs_mkdir("/boot/directory1",0); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + // add a file to the directory + copy_in_a_file("/boot/directory1/file with a long name","xxx"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + // Attempt to delete directory (should fail) + + r = yaffs_rmdir("/boot/directory1"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + // Delete file first, then rmdir should work + r = yaffs_unlink("/boot/directory1/file with a long name"); + r = yaffs_rmdir("/boot/directory1"); + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + +#if 0 + fill_disk_and_delete("/boot",20,20); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); +#endif + + yaffs_symlink("yyfile","/boot/slink"); + + yaffs_readlink("/boot/slink",str,100); + printf("symlink alias is %s\n",str); + + + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot (using stat instead of lstat)\n"); + dumpDirFollow("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + h = yaffs_open("/boot/slink",O_RDWR,0); + + printf("file length is %d\n",(int)yaffs_lseek(h,0,SEEK_END)); + + yaffs_close(h); + + yaffs_unlink("/boot/slink"); + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check chmod + + yaffs_stat("/boot/yyfile",&ystat); + temp_mode = ystat.st_mode; + + yaffs_chmod("/boot/yyfile",0x55555); + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + yaffs_chmod("/boot/yyfile",temp_mode); + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Permission checks... + PermissionsCheck("/boot/yyfile",0, O_WRONLY,0); + PermissionsCheck("/boot/yyfile",0, O_RDONLY,0); + PermissionsCheck("/boot/yyfile",0, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IREAD, O_WRONLY,0); + PermissionsCheck("/boot/yyfile",S_IREAD, O_RDONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IWRITE, O_WRONLY,1); + PermissionsCheck("/boot/yyfile",S_IWRITE, O_RDONLY,0); + PermissionsCheck("/boot/yyfile",S_IWRITE, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_WRONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_RDONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_RDWR,1); + + yaffs_chmod("/boot/yyfile",temp_mode); + + //create a zero-length file and unlink it (test for scan bug) + + h = yaffs_open("/boot/zlf",O_CREAT | O_TRUNC | O_RDWR,0); + yaffs_close(h); + + yaffs_unlink("/boot/zlf"); + + + yaffs_DumpDevStruct("/boot"); + + fill_disk_and_delete("/boot",20,20); + + yaffs_DumpDevStruct("/boot"); + + fill_files("/boot",1,10000,0); + fill_files("/boot",1,10000,5000); + fill_files("/boot",2,10000,0); + fill_files("/boot",2,10000,5000); + + leave_unlinked_file("/data",20000,0); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + + yaffs_DumpDevStruct("/boot"); + yaffs_DumpDevStruct("/data"); + + + + return 0; + +} + +int long_test_on_path(char *path) +{ + + int f; + int r; + char buffer[20]; + + char str[100]; + char name[100]; + char name2[100]; + + int h; + mode_t temp_mode; + struct yaffs_stat ystat; + + yaffs_StartUp(); + + yaffs_mount(path); + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); + + //leave_unlinked_file("/flash",20000,0); + //leave_unlinked_file("/data",20000,0); + + leave_unlinked_file(path,20,0); + + + sprintf(name,"%s/%s",path,"b1"); + f = yaffs_open(name, O_RDONLY,0); + + printf("open %s readonly, f=%d\n",name,f); + + f = yaffs_open(name, O_CREAT,S_IREAD | S_IWRITE); + + printf("open %s O_CREAT, f=%d\n",name,f); + + + r = yaffs_write(f,"hello",1); + printf("write %d attempted to write to a read-only file\n",r); + + r = yaffs_close(f); + + printf("close %d\n",r); + + f = yaffs_open(name, O_RDWR,0); + + printf("open %s O_RDWR,f=%d\n",name,f); + + + r = yaffs_write(f,"hello",2); + printf("write %d attempted to write to a writeable file\n",r); + r = yaffs_write(f,"world",3); + printf("write %d attempted to write to a writeable file\n",r); + + r= yaffs_lseek(f,0,SEEK_END); + printf("seek end %d\n",r); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + r= yaffs_lseek(f,0,SEEK_SET); + printf("seek set %d\n",r); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + + // Check values reading at end. + // A read past end of file should return 0 for 0 bytes read. + + r= yaffs_lseek(f,0,SEEK_END); + r = yaffs_read(f,buffer,10); + printf("read at end returned %d\n",r); + r= yaffs_lseek(f,500,SEEK_END); + r = yaffs_read(f,buffer,10); + printf("read past end returned %d\n",r); + + r = yaffs_close(f); + + printf("close %d\n",r); + + sprintf(name,"%s/%s",path,"yyfile"); + copy_in_a_file(name,"xxx"); + + // Create a file with a long name + sprintf(name,"%s/%s",path,"file with a long name"); + copy_in_a_file(name,"xxx"); + + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); + + // Check stat + r = yaffs_stat(name,&ystat); + + // Check rename + sprintf(name2,"%s/%s",path,"r1"); + r = yaffs_rename(name,name2); + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); + + // Check unlink + r = yaffs_unlink(name2); + + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); + + // Check mkdir + + sprintf(name,"%s/%s",path,"directory1"); + r = yaffs_mkdir(name,0); + + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); + printf("\nDirectory look-up of %s\n",name); + dumpDir(name); + + // add a file to the directory + sprintf(name2,"%s/%s",name,"/file in dir with a long name"); + copy_in_a_file(name2,"xxx"); + + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); + printf("\nDirectory look-up of %s\n",name); + dumpDir(name); + + // Attempt to delete directory (should fail) + + r = yaffs_rmdir(name); + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); + printf("\nDirectory look-up of %s\n",name); + dumpDir(name); + + yaffs_unmount(path); + + return 0; + // Delete file first, then rmdir should work + r = yaffs_unlink(name2); + r = yaffs_rmdir(name); + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); + printf("\nDirectory look-up of %s\n",name); + dumpDir(name); + +#if 0 + fill_disk_and_delete(path,20,20); + + printf("\nDirectory look-up of %s\n",path); + dumpDir(path); +#endif + + yaffs_unmount(path); + + return 0; + + yaffs_symlink("yyfile","/boot/slink"); + + yaffs_readlink("/boot/slink",str,100); + printf("symlink alias is %s\n",str); + + + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot (using stat instead of lstat)\n"); + dumpDirFollow("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + h = yaffs_open("/boot/slink",O_RDWR,0); + + printf("file length is %d\n",yaffs_lseek(h,0,SEEK_END)); + + yaffs_close(h); + + yaffs_unlink("/boot/slink"); + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check chmod + + yaffs_stat("/boot/yyfile",&ystat); + temp_mode = ystat.st_mode; + + yaffs_chmod("/boot/yyfile",0x55555); + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + yaffs_chmod("/boot/yyfile",temp_mode); + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Permission checks... + PermissionsCheck("/boot/yyfile",0, O_WRONLY,0); + PermissionsCheck("/boot/yyfile",0, O_RDONLY,0); + PermissionsCheck("/boot/yyfile",0, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IREAD, O_WRONLY,0); + PermissionsCheck("/boot/yyfile",S_IREAD, O_RDONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IWRITE, O_WRONLY,1); + PermissionsCheck("/boot/yyfile",S_IWRITE, O_RDONLY,0); + PermissionsCheck("/boot/yyfile",S_IWRITE, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_WRONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_RDONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_RDWR,1); + + yaffs_chmod("/boot/yyfile",temp_mode); + + //create a zero-length file and unlink it (test for scan bug) + + h = yaffs_open("/boot/zlf",O_CREAT | O_TRUNC | O_RDWR,0); + yaffs_close(h); + + yaffs_unlink("/boot/zlf"); + + + yaffs_DumpDevStruct("/boot"); + + fill_disk_and_delete("/boot",20,20); + + yaffs_DumpDevStruct("/boot"); + + fill_files("/boot",1,10000,0); + fill_files("/boot",1,10000,5000); + fill_files("/boot",2,10000,0); + fill_files("/boot",2,10000,5000); + + leave_unlinked_file("/data",20000,0); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + + yaffs_DumpDevStruct("/boot"); + yaffs_DumpDevStruct("/data"); + + + return 0; + +} + +int yaffs_scan_test(const char *path) +{ +} + + + +int resize_stress_test(const char *path) +{ + int a,b,i,j; + int x; + int r; + char aname[100]; + char bname[100]; + + char abuffer[1000]; + char bbuffer[1000]; + + yaffs_StartUp(); + + yaffs_mount(path); + + sprintf(aname,"%s%s",path,"/a"); + sprintf(bname,"%s%s",path,"/b"); + + memset(abuffer,'a',1000); + memset(bbuffer,'b',1000); + + a = yaffs_open(aname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + b = yaffs_open(bname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + printf(" %s %d %s %d\n",aname,a,bname,b); + + x = 0; + + for(j = 0; j < 100; j++) + { + yaffs_lseek(a,0,SEEK_END); + + + for(i = 0; i <20000; i++) + { + //r = yaffs_lseek(b,i,SEEK_SET); + //r = yaffs_write(b,bbuffer,1000); + + if(x & 0x16) + { + // shrink + int syz = yaffs_lseek(a,0,SEEK_END); + + syz -= 500; + if(syz < 0) syz = 0; + yaffs_truncate(a,syz); + + } + else + { + //expand + r = yaffs_lseek(a,i * 500,SEEK_SET); + r = yaffs_write(a,abuffer,1000); + } + x++; + + } + } + + return 0; + +} + + +int resize_stress_test_no_grow_complex(const char *path,int iters) +{ + int a,b,i,j; + int x; + int r; + char aname[100]; + char bname[100]; + + char abuffer[1000]; + char bbuffer[1000]; + + yaffs_StartUp(); + + yaffs_mount(path); + + sprintf(aname,"%s%s",path,"/a"); + sprintf(bname,"%s%s",path,"/b"); + + memset(abuffer,'a',1000); + memset(bbuffer,'b',1000); + + a = yaffs_open(aname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + b = yaffs_open(bname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + printf(" %s %d %s %d\n",aname,a,bname,b); + + x = 0; + + for(j = 0; j < iters; j++) + { + yaffs_lseek(a,0,SEEK_END); + + + for(i = 0; i <20000; i++) + { + //r = yaffs_lseek(b,i,SEEK_SET); + //r = yaffs_write(b,bbuffer,1000); + + if(!(x%20)) + { + // shrink + int syz = yaffs_lseek(a,0,SEEK_END); + + while(syz > 4000) + { + + syz -= 2050; + if(syz < 0) syz = 0; + yaffs_truncate(a,syz); + syz = yaffs_lseek(a,0,SEEK_END); + printf("shrink to %d\n",syz); + } + + + } + else + { + //expand + r = yaffs_lseek(a,500,SEEK_END); + r = yaffs_write(a,abuffer,1000); + } + x++; + + + } + printf("file size is %d\n",yaffs_lseek(a,0,SEEK_END)); + + } + + return 0; + +} + +int resize_stress_test_no_grow(const char *path,int iters) +{ + int a,b,i,j; + int x; + int r; + char aname[100]; + char bname[100]; + + char abuffer[1000]; + char bbuffer[1000]; + + yaffs_StartUp(); + + yaffs_mount(path); + + sprintf(aname,"%s%s",path,"/a"); + sprintf(bname,"%s%s",path,"/b"); + + memset(abuffer,'a',1000); + memset(bbuffer,'b',1000); + + a = yaffs_open(aname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + b = yaffs_open(bname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + printf(" %s %d %s %d\n",aname,a,bname,b); + + x = 0; + + for(j = 0; j < iters; j++) + { + yaffs_lseek(a,0,SEEK_END); + + + for(i = 0; i <20000; i++) + { + //r = yaffs_lseek(b,i,SEEK_SET); + //r = yaffs_write(b,bbuffer,1000); + + if(!(x%20)) + { + // shrink + int syz = yaffs_lseek(a,0,SEEK_END); + + while(syz > 4000) + { + + syz -= 2050; + if(syz < 0) syz = 0; + yaffs_truncate(a,syz); + syz = yaffs_lseek(a,0,SEEK_END); + printf("shrink to %d\n",syz); + } + + + } + else + { + //expand + r = yaffs_lseek(a,-500,SEEK_END); + r = yaffs_write(a,abuffer,1000); + } + x++; + + + } + printf("file size is %d\n",yaffs_lseek(a,0,SEEK_END)); + + } + + return 0; + +} + +int directory_rename_test(void) +{ + int r; + yaffs_StartUp(); + + yaffs_mount("/ram"); + yaffs_mkdir("/ram/a",0); + yaffs_mkdir("/ram/a/b",0); + yaffs_mkdir("/ram/c",0); + + printf("\nDirectory look-up of /ram\n"); + dumpDir("/ram"); + dumpDir("/ram/a"); + dumpDir("/ram/a/b"); + + printf("Do rename (should fail)\n"); + + r = yaffs_rename("/ram/a","/ram/a/b/d"); + printf("\nDirectory look-up of /ram\n"); + dumpDir("/ram"); + dumpDir("/ram/a"); + dumpDir("/ram/a/b"); + + printf("Do rename (should not fail)\n"); + + r = yaffs_rename("/ram/c","/ram/a/b/d"); + printf("\nDirectory look-up of /ram\n"); + dumpDir("/ram"); + dumpDir("/ram/a"); + dumpDir("/ram/a/b"); + + + return 1; + +} + +int cache_read_test(void) +{ + int a,b,c; + int i; + int sizeOfFiles = 500000; + char buffer[100]; + + yaffs_StartUp(); + + yaffs_mount("/boot"); + + make_a_file("/boot/a",'a',sizeOfFiles); + make_a_file("/boot/b",'b',sizeOfFiles); + + a = yaffs_open("/boot/a",O_RDONLY,0); + b = yaffs_open("/boot/b",O_RDONLY,0); + c = yaffs_open("/boot/c", O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + do{ + i = sizeOfFiles; + if (i > 100) i = 100; + sizeOfFiles -= i; + yaffs_read(a,buffer,i); + yaffs_read(b,buffer,i); + yaffs_write(c,buffer,i); + } while(sizeOfFiles > 0); + + + + return 1; + +} + +int cache_bypass_bug_test(void) +{ + // This test reporoduces a bug whereby YAFFS caching *was* buypassed + // resulting in erroneous reads after writes. + // This bug has been fixed. + + int a; + int i; + char buffer1[1000]; + char buffer2[1000]; + + memset(buffer1,0,sizeof(buffer1)); + memset(buffer2,0,sizeof(buffer2)); + + yaffs_StartUp(); + + yaffs_mount("/boot"); + + // Create a file of 2000 bytes. + make_a_file("/boot/a",'X',2000); + + a = yaffs_open("/boot/a",O_RDWR, S_IREAD | S_IWRITE); + + // Write a short sequence to the file. + // This will go into the cache. + yaffs_lseek(a,0,SEEK_SET); + yaffs_write(a,"abcdefghijklmnopqrstuvwxyz",20); + + // Read a short sequence from the file. + // This will come from the cache. + yaffs_lseek(a,0,SEEK_SET); + yaffs_read(a,buffer1,30); + + // Read a page size sequence from the file. + yaffs_lseek(a,0,SEEK_SET); + yaffs_read(a,buffer2,512); + + printf("buffer 1 %s\n",buffer1); + printf("buffer 2 %s\n",buffer2); + + if(strncmp(buffer1,buffer2,20)) + { + printf("Cache bypass bug detected!!!!!\n"); + } + + + return 1; +} + + +int free_space_check(void) +{ + int f; + + yaffs_StartUp(); + yaffs_mount("/boot"); + fill_disk("/boot/",2); + f = yaffs_freespace("/boot"); + + printf("%d free when disk full\n",f); + return 1; +} + +int truncate_test(void) +{ + int a; + int r; + int i; + int l; + + char y[10]; + + yaffs_StartUp(); + yaffs_mount("/boot"); + + yaffs_unlink("/boot/trunctest"); + + a = yaffs_open("/boot/trunctest", O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + yaffs_write(a,"abcdefghijklmnopqrstuvwzyz",26); + + yaffs_truncate(a,3); + l= yaffs_lseek(a,0,SEEK_END); + + printf("truncated length is %d\n",l); + + yaffs_lseek(a,5,SEEK_SET); + yaffs_write(a,"1",1); + + yaffs_lseek(a,0,SEEK_SET); + + r = yaffs_read(a,y,10); + + printf("read %d bytes:",r); + + for(i = 0; i < r; i++) printf("[%02X]",y[i]); + + printf("\n"); + + return 0; + +} + + +int main(int argc, char *argv[]) +{ + //return long_test(argc,argv); + + //return cache_read_test(); + + //return resize_stress_test_no_grow("/flash",2); + + + + scan_pattern_test("/boot",40000,10); + //short_scan_test("/flash",40000,200); + return 0; + + long_test_on_path("/flash"); + long_test_on_path("/flash"); + + // cache_bypass_bug_test(); + + free_space_check(); + + return 0; + +} diff --git a/direct/yaffs_fileem.c b/direct/yaffs_fileem.c new file mode 100644 index 0000000..8295786 --- /dev/null +++ b/direct/yaffs_fileem.c @@ -0,0 +1,217 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_ramdisk.c: yaffs ram disk component + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +// This provides a YAFFS nand emulation on a file. +// THis is only intended as test code to test persistence etc. + +const char *yaffs_flashif_c_version = "$Id: yaffs_fileem.c,v 1.1 2004-11-03 08:29:28 charles Exp $"; + + +#include "yportenv.h" + +#include "yaffs_flashif.h" +#include "yaffs_guts.h" + +#include "devextras.h" + +#include +#include +#include +#include + + + +#define SIZE_IN_MB 16 + +#define BLOCK_SIZE (32 * 528) +#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512)) + + + +typedef struct +{ + __u8 data[528]; // Data + spare +} yflash_Page; + +typedef struct +{ + yflash_Page page[32]; // The pages in the block + +} yflash_Block; + + + +typedef struct +{ + int handle; + int nBlocks; +} yflash_Device; + +static yflash_Device filedisk; + +static int CheckInit(yaffs_Device *dev) +{ + static int initialised = 0; + + int i; + + + int fSize; + int written; + + yflash_Page p; + + if(initialised) + { + return YAFFS_OK; + } + + initialised = 1; + + + filedisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024); + + filedisk.handle = open("yaffsemfile", O_RDWR | O_CREAT, S_IREAD | S_IWRITE); + + if(filedisk.handle < 0) + { + perror("Failed to open yaffs emulation file"); + return YAFFS_FAIL; + } + + + fSize = lseek(filedisk.handle,0,SEEK_END); + + if(fSize < SIZE_IN_MB * 1024 * 1024) + { + printf("Creating yaffs emulation file\n"); + + lseek(filedisk.handle,0,SEEK_SET); + + memset(&p,0xff,sizeof(yflash_Page)); + + for(i = 0; i < SIZE_IN_MB * 1024 * 1024; i+= 512) + { + written = write(filedisk.handle,&p,sizeof(yflash_Page)); + + if(written != sizeof(yflash_Page)) + { + printf("Write failed\n"); + return YAFFS_FAIL; + } + } + } + + return 1; +} + +int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare) +{ + int written; + + CheckInit(dev); + + + + if(data) + { + lseek(filedisk.handle,chunkInNAND * 528,SEEK_SET); + written = write(filedisk.handle,data,512); + + if(written != 512) return YAFFS_FAIL; + } + + if(spare) + { + lseek(filedisk.handle,chunkInNAND * 528 + 512,SEEK_SET); + written = write(filedisk.handle,spare,16); + + if(written != 16) return YAFFS_FAIL; + } + + + return YAFFS_OK; + +} + + +int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare) +{ + int nread; + + CheckInit(dev); + + + + if(data) + { + lseek(filedisk.handle,chunkInNAND * 528,SEEK_SET); + nread = read(filedisk.handle,data,512); + + if(nread != 512) return YAFFS_FAIL; + } + + if(spare) + { + lseek(filedisk.handle,chunkInNAND * 528 + 512,SEEK_SET); + nread= read(filedisk.handle,spare,16); + + if(nread != 16) return YAFFS_FAIL; + } + + + return YAFFS_OK; + +} + + +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + int i; + + CheckInit(dev); + + if(blockNumber < 0 || blockNumber >= filedisk.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + return YAFFS_FAIL; + } + else + { + + yflash_Page pg; + + memset(&pg,0xff,sizeof(yflash_Page)); + + lseek(filedisk.handle, blockNumber * 32 * 528, SEEK_SET); + + for(i = 0; i < 32; i++) + { + write(filedisk.handle,&pg,528); + } + return YAFFS_OK; + } + +} + +int yflash_InitialiseNAND(yaffs_Device *dev) +{ + dev->useNANDECC = 1; // force on useNANDECC which gets faked. + // This saves us doing ECC checks. + + return YAFFS_OK; +} + + diff --git a/direct/yaffs_fileem2k.c b/direct/yaffs_fileem2k.c new file mode 100644 index 0000000..069cb19 --- /dev/null +++ b/direct/yaffs_fileem2k.c @@ -0,0 +1,307 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_ramdisk.c: yaffs ram disk component + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +// This provides a YAFFS nand emulation on a file for emulating 2kB pages. +// THis is only intended as test code to test persistence etc. + +const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.1 2004-11-03 08:29:28 charles Exp $"; + + +#include "yportenv.h" + +#include "yaffs_flashif.h" +#include "yaffs_guts.h" +#include "devextras.h" + +#include +#include +#include +#include + +#include "yaffs_fileem2k.h" +#include "yaffs_packedtags.h" + + + +typedef struct +{ + __u8 data[PAGE_SIZE]; // Data + spare +} yflash_Page; + +typedef struct +{ + yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block + +} yflash_Block; + + + +typedef struct +{ + int handle; + int nBlocks; +} yflash_Device; + +static yflash_Device filedisk; + +static int CheckInit(yaffs_Device *dev) +{ + static int initialised = 0; + + int i; + + + int fSize; + int written; + + yflash_Page p; + + if(initialised) + { + return YAFFS_OK; + } + + initialised = 1; + + + filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB; + + filedisk.handle = open("yaffsemfile2k", O_RDWR | O_CREAT, S_IREAD | S_IWRITE); + + if(filedisk.handle < 0) + { + perror("Failed to open yaffs emulation file"); + return YAFFS_FAIL; + } + + + fSize = lseek(filedisk.handle,0,SEEK_END); + + if(fSize < filedisk.nBlocks * BLOCK_SIZE) + { + printf("Creating yaffs emulation file\n"); + + lseek(filedisk.handle,0,SEEK_SET); + + memset(&p,0xff,sizeof(yflash_Page)); + + for(i = 0; i < filedisk.nBlocks * BLOCK_SIZE; i+= PAGE_SIZE) + { + written = write(filedisk.handle,&p,sizeof(yflash_Page)); + + if(written != sizeof(yflash_Page)) + { + printf("Write failed\n"); + return YAFFS_FAIL; + } + } + } + + return 1; +} + +int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags) +{ + int written; + int pos; + + CheckInit(dev); + + + + if(data) + { + pos = chunkInNAND * PAGE_SIZE; + lseek(filedisk.handle,pos,SEEK_SET); + written = write(filedisk.handle,data,dev->nBytesPerChunk); + + if(written != dev->nBytesPerChunk) return YAFFS_FAIL; + } + + if(tags) + { + pos = chunkInNAND * PAGE_SIZE + PAGE_DATA_SIZE; + lseek(filedisk.handle,pos,SEEK_SET); + if(dev->isYaffs2) + { + + written = write(filedisk.handle,tags,sizeof(yaffs_ExtendedTags)); + if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL; + } + else + { + yaffs_PackedTags pt; + yaffs_PackTags(&pt,tags); + + written = write(filedisk.handle,&pt,sizeof(pt)); + if(written != sizeof(pt)) return YAFFS_FAIL; + } + } + + + return YAFFS_OK; + +} + +int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) +{ + int written; + + yaffs_PackedTags pt; + + CheckInit(dev); + + memset(&pt,0,sizeof(pt)); + lseek(filedisk.handle,(blockNo * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET); + written = write(filedisk.handle,&pt,sizeof(pt)); + + if(written != sizeof(pt)) return YAFFS_FAIL; + + + return YAFFS_OK; + +} + +int yaffs_CheckAllFF(const __u8 *ptr, int n) +{ + while(n) + { + n--; + if(*ptr!=0xFF) return 0; + ptr++; + } + return 1; +} + + +int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) +{ + int nread; + int pos; + + CheckInit(dev); + + + + if(data) + { + pos = chunkInNAND * PAGE_SIZE; + lseek(filedisk.handle,pos,SEEK_SET); + nread = read(filedisk.handle,data,dev->nBytesPerChunk); + + if(nread != dev->nBytesPerChunk) return YAFFS_FAIL; + } + + if(tags) + { + pos = chunkInNAND * PAGE_SIZE + PAGE_DATA_SIZE; + lseek(filedisk.handle,pos,SEEK_SET); + if(dev->isYaffs2) + { + nread= read(filedisk.handle,tags,sizeof(yaffs_ExtendedTags)); + if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL; + if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags))) + { + yaffs_InitialiseTags(tags); + } + else + { + tags->chunkUsed = 1; + } + } + else + { + yaffs_PackedTags pt; + nread= read(filedisk.handle,&pt,sizeof(pt)); + yaffs_UnpackTags(tags,&pt); + if(nread != sizeof(pt)) return YAFFS_FAIL; + } + } + + + return YAFFS_OK; + +} + + +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + int i; + + CheckInit(dev); + + if(blockNumber < 0 || blockNumber >= filedisk.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + return YAFFS_FAIL; + } + else + { + + __u8 pg[PAGE_SIZE]; + int syz = PAGE_SIZE; + int pos; + + memset(pg,0xff,syz); + + pos = lseek(filedisk.handle, blockNumber * dev->nChunksPerBlock * PAGE_SIZE, SEEK_SET); + + for(i = 0; i < dev->nChunksPerBlock; i++) + { + write(filedisk.handle,pg,PAGE_SIZE); + } + pos = lseek(filedisk.handle, 0,SEEK_CUR); + + return YAFFS_OK; + } + +} + +int yflash_InitialiseNAND(yaffs_Device *dev) +{ + CheckInit(dev); + + return YAFFS_OK; +} + + + + +int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) +{ + yaffs_ExtendedTags tags; + int chunkNo; + + *sequenceNumber = 0; + + chunkNo = blockNo * dev->nChunksPerBlock; + + yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags); + if(tags.blockBad) + { + *state = YAFFS_BLOCK_STATE_DEAD; + } + else if(!tags.chunkUsed) + { + *state = YAFFS_BLOCK_STATE_EMPTY; + } + else if(tags.chunkUsed) + { + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; + *sequenceNumber = tags.sequenceNumber; + } + return YAFFS_OK; +} + diff --git a/direct/yaffs_fileem2k.h b/direct/yaffs_fileem2k.h new file mode 100644 index 0000000..6aa731f --- /dev/null +++ b/direct/yaffs_fileem2k.h @@ -0,0 +1,45 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_ramdisk.c: yaffs ram disk component + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __FILEEM2K_H__ +#define __FILEEM2K_H__ + +#if 1 + +#define SIZE_IN_MB 512 +#define PAGE_DATA_SIZE (2048) +#define PAGE_SPARE_SIZE (64) +#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE) +#define PAGES_PER_BLOCK (64) +#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK) +#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE)) +#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE) +#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB) + +#else + +#define SIZE_IN_MB 128 +#define PAGE_DATA_SIZE (512) +#define SPARE_SIZE (16) +#define PAGE_SIZE (PAGE_DATA_SIZE + SPARE_SIZE) +#define PAGES_PER_BLOCK (32) +#define BLOCK_DATA_SIZE (PAGE_SIZE * PAGES_PER_BLOCK) +#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE)) +#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE) +#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB) + +#endif + +#endif + diff --git a/direct/yaffs_flashif.c b/direct/yaffs_flashif.c new file mode 100644 index 0000000..73c07c8 --- /dev/null +++ b/direct/yaffs_flashif.c @@ -0,0 +1,233 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_ramdisk.c: yaffs ram disk component + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +// This provides a rma disk under yaffs. +// NB this is not intended for NAND emulation. +// Use this with dev->useNANDECC enabled, then ECC overheads are not required. + +const char *yaffs_flashif_c_version = "$Id: yaffs_flashif.c,v 1.1 2004-11-03 08:29:28 charles Exp $"; + + +#include "yportenv.h" + +#include "yaffs_flashif.h" +#include "yaffs_guts.h" +#include "devextras.h" + + +#define SIZE_IN_MB 16 + +#define BLOCK_SIZE (32 * 528) +#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512)) + + + +typedef struct +{ + __u8 data[528]; // Data + spare +} yflash_Page; + +typedef struct +{ + yflash_Page page[32]; // The pages in the block + +} yflash_Block; + + + +typedef struct +{ + yflash_Block **block; + int nBlocks; +} yflash_Device; + +static yflash_Device ramdisk; + +static int CheckInit(yaffs_Device *dev) +{ + static int initialised = 0; + + int i; + int fail = 0; + int nAllocated = 0; + + if(initialised) + { + return YAFFS_OK; + } + + initialised = 1; + + + ramdisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024); + + ramdisk.block = YMALLOC(sizeof(yflash_Block *) * ramdisk.nBlocks); + + if(!ramdisk.block) return 0; + + for(i=0; i page[pg].data,data,512); + } + + + if(tags) + { + yaffs_PackedTags pt; + yaffs_PackTags(&pt,tags); + memcpy(&ramdisk.block[blk]->page[pg].data[512],&pt,sizeof(pt)); + } + + return YAFFS_OK; + +} + + +int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Tags *tags) +{ + int blk; + int pg; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + if(data) + { + memcpy(data,ramdisk.block[blk]->page[pg].data,512); + } + + + if(tags) + { + yaffs_PackedTags pt; + memcpy(&pt,&ramdisk.block[blk]->page[pg].data[512],sizeof(yaffs_PackedTags)); + yaffs_UnpackTags(tags,&pt); + } + + return YAFFS_OK; +} + + +int yflash_CheckChunkErased(yaffs_Device *dev,int chunkInNAND) +{ + int blk; + int pg; + int i; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + for(i = 0; i < 528; i++) + { + if(ramdisk.block[blk]->page[pg].data[i] != 0xFF) + { + return YAFFS_FAIL; + } + } + + return YAFFS_OK; + +} + +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + CheckInit(dev); + + if(blockNumber < 0 || blockNumber >= ramdisk.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + return YAFFS_FAIL; + } + else + { + memset(ramdisk.block[blockNumber],0xFF,sizeof(yflash_Block)); + return YAFFS_OK; + } + +} + +int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) +{ + return YAFFS_OK; + +} +int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) +{ + *state = YAFFS_BLOCK_STATE_EMPTY; + *sequenceNumber = 0; +} + + +int yflash_InitialiseNAND(yaffs_Device *dev) +{ + return YAFFS_OK; +} + diff --git a/direct/yaffs_flashif.h b/direct/yaffs_flashif.h new file mode 100644 index 0000000..5eb138a --- /dev/null +++ b/direct/yaffs_flashif.h @@ -0,0 +1,35 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_ramdisk.h: yaffs ram disk component + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * $Id: yaffs_flashif.h,v 1.1 2004-11-03 08:29:28 charles Exp $ + */ + +// This provides a rma disk under yaffs. +// NB this is not intended for NAND emulation. +// Use this with dev->useNANDECC enabled, then ECC overheads are not required. + +#ifndef __YAFFS_FLASH_H__ +#define __YAFFS_FLASH_H__ + + +#include "yaffs_guts.h" +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare); +int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags); +int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare); +int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags); +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yflash_InitialiseNAND(yaffs_Device *dev); +int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); +int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber); + +#endif diff --git a/direct/yaffs_packedtags.c b/direct/yaffs_packedtags.c new file mode 100644 index 0000000..6214a71 --- /dev/null +++ b/direct/yaffs_packedtags.c @@ -0,0 +1,42 @@ +#include "yaffs_packedtags.h" +#include + +void yaffs_PackTags(yaffs_PackedTags *pt, yaffs_ExtendedTags *t) +{ + pt->chunkId = t->chunkId; + pt->serialNumber = t->serialNumber; + pt->byteCount = t->byteCount; + pt->objectId = t->objectId; + pt->ecc = 0; + pt->deleted = (t->chunkDeleted) ? 0 : 1; + pt->unusedStuff = 0; + pt->shouldBeFF = 0xFFFFFFFF; + +} + +void yaffs_UnpackTags(yaffs_ExtendedTags *t, yaffs_PackedTags *pt) +{ + static __u8 allFF[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff}; + + if(memcmp(allFF,pt,sizeof(yaffs_PackedTags))) + { + t->blockBad = 0; + if(pt->shouldBeFF != 0xFFFFFFFF) + { + t->blockBad = 1; + } + t->chunkUsed = 1; + t->objectId = pt->objectId; + t->chunkId = pt->chunkId; + t->byteCount = pt->byteCount; + t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; + t->chunkDeleted = (pt->deleted) ? 0 : 1; + t->serialNumber = pt->serialNumber; + } + else + { + memset(t,0,sizeof(yaffs_ExtendedTags)); + + } +} + diff --git a/direct/yaffs_packedtags.h b/direct/yaffs_packedtags.h new file mode 100644 index 0000000..d0790d5 --- /dev/null +++ b/direct/yaffs_packedtags.h @@ -0,0 +1,24 @@ + +#ifndef __YAFFS_PACKEDTAGS_H__ +#define __YAFFS_PACKEDTAGS_H__ + +#include "yaffs_guts.h" + +typedef struct +{ + unsigned chunkId:20; + unsigned serialNumber:2; + unsigned byteCount:10; + unsigned objectId:18; + unsigned ecc:12; + unsigned deleted:1; + unsigned unusedStuff:1; + unsigned shouldBeFF; + +} yaffs_PackedTags; + +void yaffs_PackTags(yaffs_PackedTags *pt, yaffs_ExtendedTags *t); +void yaffs_UnpackTags(yaffs_ExtendedTags *t, yaffs_PackedTags *pt); +#endif + + diff --git a/direct/yaffs_ramdisk.c b/direct/yaffs_ramdisk.c new file mode 100644 index 0000000..b19d6cb --- /dev/null +++ b/direct/yaffs_ramdisk.c @@ -0,0 +1,232 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_ramdisk.c: yaffs ram disk component + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +// This provides a rma disk under yaffs. +// NB this is not intended for NAND emulation. +// Use this with dev->useNANDECC enabled, then ECC overheads are not required. + +const char *yaffs_ramdisk_c_version = "$Id: yaffs_ramdisk.c,v 1.1 2004-11-03 08:29:28 charles Exp $"; + + +#include "yportenv.h" + +#include "yaffs_ramdisk.h" +#include "yaffs_guts.h" +#include "devextras.h" +#include "yaffs_packedtags.h" + + + +#define SIZE_IN_MB 2 + +#define BLOCK_SIZE (32 * 528) +#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512)) + + + + + +typedef struct +{ + __u8 data[528]; // Data + spare +} yramdisk_Page; + +typedef struct +{ + yramdisk_Page page[32]; // The pages in the block + +} yramdisk_Block; + + + +typedef struct +{ + yramdisk_Block **block; + int nBlocks; +} yramdisk_Device; + +static yramdisk_Device ramdisk; + +static int CheckInit(yaffs_Device *dev) +{ + static int initialised = 0; + + int i; + int fail = 0; + //int nBlocks; + int nAllocated = 0; + + if(initialised) + { + return YAFFS_OK; + } + + initialised = 1; + + + ramdisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024); + + ramdisk.block = YMALLOC(sizeof(yramdisk_Block *) * ramdisk.nBlocks); + + if(!ramdisk.block) return 0; + + for(i=0; i page[pg].data,data,512); + } + + + if(tags) + { + yaffs_PackedTags pt; + + yaffs_PackTags(&pt,tags); + memcpy(&ramdisk.block[blk]->page[pg].data[512],&pt,sizeof(pt)); + } + + return YAFFS_OK; + +} + + +int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) +{ + int blk; + int pg; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + if(data) + { + memcpy(data,ramdisk.block[blk]->page[pg].data,512); + } + + + if(tags) + { + yaffs_PackedTags pt; + + memcpy(&pt,&ramdisk.block[blk]->page[pg].data[512],sizeof(pt)); + yaffs_UnpackTags(tags,&pt); + + } + + return YAFFS_OK; +} + + +int yramdisk_CheckChunkErased(yaffs_Device *dev,int chunkInNAND) +{ + int blk; + int pg; + int i; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + for(i = 0; i < 528; i++) + { + if(ramdisk.block[blk]->page[pg].data[i] != 0xFF) + { + return YAFFS_FAIL; + } + } + + return YAFFS_OK; + +} + +int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + CheckInit(dev); + + if(blockNumber < 0 || blockNumber >= ramdisk.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + return YAFFS_FAIL; + } + else + { + memset(ramdisk.block[blockNumber],0xFF,sizeof(yramdisk_Block)); + return YAFFS_OK; + } + +} + +int yramdisk_InitialiseNAND(yaffs_Device *dev) +{ + //dev->useNANDECC = 1; // force on useNANDECC which gets faked. + // This saves us doing ECC checks. + + return YAFFS_OK; +} + + diff --git a/direct/yaffs_ramdisk.h b/direct/yaffs_ramdisk.h new file mode 100644 index 0000000..8ada72a --- /dev/null +++ b/direct/yaffs_ramdisk.h @@ -0,0 +1,32 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_ramdisk.h: yaffs ram disk component + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * $Id: yaffs_ramdisk.h,v 1.1 2004-11-03 08:29:28 charles Exp $ + */ + +// This provides a rma disk under yaffs. +// NB this is not intended for NAND emulation. +// Use this with dev->useNANDECC enabled, then ECC overheads are not required. + +#ifndef __YAFFS_RAMDISK_H__ +#define __YAFFS_RAMDISK_H__ + + +#include "yaffs_guts.h" +int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags); +int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags); +int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yramdisk_InitialiseNAND(yaffs_Device *dev); +int yramdisk_MarkNANDBlockBad(yaffs_Device *dev,int blockNumber); +int yramdisk_QueryNANDBlock(yaffs_Device *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber); +#endif diff --git a/direct/yaffscfg.c b/direct/yaffscfg.c new file mode 100644 index 0000000..42c9dd2 --- /dev/null +++ b/direct/yaffscfg.c @@ -0,0 +1,122 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffscfg.c The configuration for the "direct" use of yaffs. + * + * This file is intended to be modified to your requirements. + * There is no need to redistribute this file. + */ + +#include "yaffscfg.h" +#include "yaffsfs.h" +#include + +unsigned yaffs_traceMask = 0xFFFFFFFF; + + +void yaffsfs_SetError(int err) +{ + //Do whatever to set error + errno = err; +} + +void yaffsfs_Lock(void) +{ +} + +void yaffsfs_Unlock(void) +{ +} + +__u32 yaffsfs_CurrentTime(void) +{ + return 0; +} + +void yaffsfs_LocalInitialisation(void) +{ + // Define locking semaphore. +} + +// Configuration for: +// /ram 2MB ramdisk +// /boot 2MB boot disk (flash) +// /flash 14MB flash disk (flash) +// NB Though /boot and /flash occupy the same physical device they +// are still disticnt "yaffs_Devices. You may think of these as "partitions" +// using non-overlapping areas in the same device. +// + +#include "yaffs_ramdisk.h" +#include "yaffs_flashif.h" + +static yaffs_Device ramDev; +static yaffs_Device bootDev; +static yaffs_Device flashDev; + +static yaffsfs_DeviceConfiguration yaffsfs_config[] = { + + { "/ram", &ramDev}, + { "/boot", &bootDev}, + { "/flash", &flashDev}, + {(void *)0,(void *)0} +}; + + +int yaffs_StartUp(void) +{ + // Stuff to configure YAFFS + // Stuff to initialise anything special (eg lock semaphore). + yaffsfs_LocalInitialisation(); + + // Set up devices + + // /ram + ramDev.nBytesPerChunk = 512; + ramDev.nChunksPerBlock = 32; + ramDev.nReservedBlocks = 2; // Set this smaller for RAM + ramDev.startBlock = 1; // Can't use block 0 + ramDev.endBlock = 127; // Last block in 2MB. + ramDev.useNANDECC = 1; + ramDev.nShortOpCaches = 0; // Disable caching on this device. + ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat. + ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND; + ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND; + ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND; + ramDev.initialiseNAND = yramdisk_InitialiseNAND; + + // /boot + bootDev.nBytesPerChunk = 612; + bootDev.nChunksPerBlock = 32; + bootDev.nReservedBlocks = 5; + bootDev.startBlock = 1; // Can't use block 0 + bootDev.endBlock = 127; // Last block in 2MB. + bootDev.useNANDECC = 0; // use YAFFS's ECC + bootDev.nShortOpCaches = 10; // Use caches + bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat. + bootDev.writeChunkToNAND = yflash_WriteChunkToNAND; + bootDev.readChunkFromNAND = yflash_ReadChunkFromNAND; + bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND; + bootDev.initialiseNAND = yflash_InitialiseNAND; + + // /flash + flashDev.nBytesPerChunk = 512; + flashDev.nChunksPerBlock = 32; + flashDev.nReservedBlocks = 5; + flashDev.startBlock = 128; // First block after 2MB + flashDev.endBlock = 1023; // Last block in 16MB + flashDev.useNANDECC = 0; // use YAFFS's ECC + flashDev.nShortOpCaches = 10; // Use caches + flashDev.genericDevice = (void *) 2; // Used to identify the device in fstat. + flashDev.writeChunkToNAND = yflash_WriteChunkToNAND; + flashDev.readChunkFromNAND = yflash_ReadChunkFromNAND; + flashDev.eraseBlockInNAND = yflash_EraseBlockInNAND; + flashDev.initialiseNAND = yflash_InitialiseNAND; + + yaffs_initialise(yaffsfs_config); + + return 0; +} + + + + diff --git a/direct/yaffscfg.h b/direct/yaffscfg.h new file mode 100644 index 0000000..4325aa2 --- /dev/null +++ b/direct/yaffscfg.h @@ -0,0 +1,30 @@ +/* +* Header file for using yaffs in an application via +* a direct interface. +*/ + + +#ifndef __YAFFSCFG_H__ +#define __YAFFSCFG_H__ + + +#include "devextras.h" + +#define YAFFSFS_N_HANDLES 200 + + +typedef struct { + const char *prefix; + struct yaffs_DeviceStruct *dev; +} yaffsfs_DeviceConfiguration; + + +void yaffsfs_Lock(void); +void yaffsfs_Unlock(void); + +__u32 yaffsfs_CurrentTime(void); + +void yaffsfs_SetError(int err); + +#endif + diff --git a/direct/yaffscfg2k.c b/direct/yaffscfg2k.c new file mode 100644 index 0000000..379846b --- /dev/null +++ b/direct/yaffscfg2k.c @@ -0,0 +1,137 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffscfg.c The configuration for the "direct" use of yaffs. + * + * This file is intended to be modified to your requirements. + * There is no need to redistribute this file. + */ + +#include "yaffscfg.h" +#include "yaffsfs.h" +#include "yaffs_fileem2k.h" + +#include + +unsigned yaffs_traceMask = 0xFFFFFFFF; + + +void yaffsfs_SetError(int err) +{ + //Do whatever to set error + errno = err; +} + +void yaffsfs_Lock(void) +{ +} + +void yaffsfs_Unlock(void) +{ +} + +__u32 yaffsfs_CurrentTime(void) +{ + return 0; +} + +void yaffsfs_LocalInitialisation(void) +{ + // Define locking semaphore. +} + +// Configuration for: +// /ram 2MB ramdisk +// /boot 2MB boot disk (flash) +// /flash 14MB flash disk (flash) +// NB Though /boot and /flash occupy the same physical device they +// are still disticnt "yaffs_Devices. You may think of these as "partitions" +// using non-overlapping areas in the same device. +// + +#include "yaffs_ramdisk.h" +#include "yaffs_flashif.h" + +static yaffs_Device ramDev; +static yaffs_Device bootDev; +static yaffs_Device flashDev; + +static yaffsfs_DeviceConfiguration yaffsfs_config[] = { + + { "/ram", &ramDev}, + { "/boot", &bootDev}, + { "/flash", &flashDev}, + {(void *)0,(void *)0} +}; + + +int yaffs_StartUp(void) +{ + // Stuff to configure YAFFS + // Stuff to initialise anything special (eg lock semaphore). + yaffsfs_LocalInitialisation(); + + // Set up devices + // /ram + memset(&ramDev,0,sizeof(ramDev)); + ramDev.nBytesPerChunk = 512; + ramDev.nChunksPerBlock = 32; + ramDev.nReservedBlocks = 2; // Set this smaller for RAM + ramDev.startBlock = 1; // Can't use block 0 + ramDev.endBlock = 127; // Last block in 2MB. + //ramDev.useNANDECC = 1; + ramDev.nShortOpCaches = 0; // Disable caching on this device. + ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat. + ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND; + ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND; + ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND; + ramDev.initialiseNAND = yramdisk_InitialiseNAND; + + // /boot + memset(&bootDev,0,sizeof(bootDev)); + bootDev.nBytesPerChunk = 512; + bootDev.nChunksPerBlock = 32; + bootDev.nReservedBlocks = 5; + bootDev.startBlock = 1; // Can't use block 0 + bootDev.endBlock = 63; // Last block + //bootDev.useNANDECC = 0; // use YAFFS's ECC + bootDev.nShortOpCaches = 10; // Use caches + bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat. + bootDev.writeChunkWithTagsToNAND = yflash_WriteChunkWithTagsToNAND; + bootDev.readChunkWithTagsFromNAND = yflash_ReadChunkWithTagsFromNAND; + bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND; + bootDev.initialiseNAND = yflash_InitialiseNAND; + bootDev.markNANDBlockBad = yflash_MarkNANDBlockBad; + bootDev.queryNANDBlock = yflash_QueryNANDBlock; + + + + // /flash + // Set this puppy up to use + // the file emulation space as + // 2kpage/64chunk per block/128MB device + memset(&flashDev,0,sizeof(flashDev)); + + flashDev.nBytesPerChunk = 2048; + flashDev.nChunksPerBlock = 64; + flashDev.nReservedBlocks = 5; + flashDev.startBlock = 64; // First block after /boot + //flashDev.endBlock = 127; // Last block in 16MB + flashDev.endBlock = (512 * 1024 * 1024)/(flashDev.nBytesPerChunk * flashDev.nChunksPerBlock) - 1; // Last block in 512MB + flashDev.isYaffs2 = 1; + flashDev.nShortOpCaches = 10; // Use caches + flashDev.genericDevice = (void *) 2; // Used to identify the device in fstat. + flashDev.writeChunkWithTagsToNAND = yflash_WriteChunkWithTagsToNAND; + flashDev.readChunkWithTagsFromNAND = yflash_ReadChunkWithTagsFromNAND; + flashDev.eraseBlockInNAND = yflash_EraseBlockInNAND; + flashDev.initialiseNAND = yflash_InitialiseNAND; + flashDev.markNANDBlockBad = yflash_MarkNANDBlockBad; + flashDev.queryNANDBlock = yflash_QueryNANDBlock; + + yaffs_initialise(yaffsfs_config); + + return 0; +} + + + + diff --git a/direct/yaffsfs.c b/direct/yaffsfs.c new file mode 100644 index 0000000..1c73c99 --- /dev/null +++ b/direct/yaffsfs.c @@ -0,0 +1,1412 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffsfs.c The interface functions for using YAFFS via a "direct" interface. + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include "yaffsfs.h" +#include "yaffs_guts.h" +#include "yaffscfg.h" +#include // for memset +#include "yportenv.h" + +#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5 + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.1 2004-11-03 08:29:28 charles Exp $"; + +// configurationList is the list of devices that are supported +static yaffsfs_DeviceConfiguration *yaffsfs_configurationList; + + +// +// Directory search context +// +// NB this is an opaque structure. + +struct yaffsfs_ObjectListEntry +{ + int objectId; + struct yaffsfs_ObjectListEntry *next; +}; + + +typedef struct +{ + __u32 magic; + yaffs_dirent de; + struct yaffsfs_ObjectListEntry *list; + char name[NAME_MAX+1]; + +} yaffsfs_DirectorySearchContext; + + +// Handle management. +// + +typedef struct +{ + __u8 inUse:1; // this handle is in use + __u8 readOnly:1; // this handle is read only + __u8 append:1; // append only + __u8 exclusive:1; // exclusive + __u32 position; // current position in file + yaffs_Object *obj; // the object +}yaffsfs_Handle; + + +static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth); + + + +static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES]; + +// yaffsfs_InitHandle +/// Inilitalise handles on start-up. +// +static int yaffsfs_InitHandles(void) +{ + int i; + for(i = 0; i < YAFFSFS_N_HANDLES; i++) + { + yaffsfs_handle[i].inUse = 0; + yaffsfs_handle[i].obj = NULL; + } + return 0; +} + +yaffsfs_Handle *yaffsfs_GetHandlePointer(int h) +{ + if(h < 0 || h >= YAFFSFS_N_HANDLES) + { + return NULL; + } + + return &yaffsfs_handle[h]; +} + +yaffs_Object *yaffsfs_GetHandleObject(int handle) +{ + yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle); + + if(h && h->inUse) + { + return h->obj; + } + + return NULL; +} + + +//yaffsfs_GetHandle +// Grab a handle (when opening a file) +// + +static int yaffsfs_GetHandle(void) +{ + int i; + yaffsfs_Handle *h; + + for(i = 0; i < YAFFSFS_N_HANDLES; i++) + { + h = yaffsfs_GetHandlePointer(i); + if(!h) + { + // todo bug: should never happen + } + if(!h->inUse) + { + memset(h,0,sizeof(yaffsfs_Handle)); + h->inUse=1; + return i; + } + } + return -1; +} + +// yaffs_PutHandle +// Let go of a handle (when closing a file) +// +static int yaffsfs_PutHandle(int handle) +{ + yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle); + + if(h) + { + h->inUse = 0; + h->obj = NULL; + } + return 0; +} + + + +// Stuff to search for a directory from a path + + +int yaffsfs_Match(char a, char b) +{ + // case sensitive + return (a == b); +} + +// yaffsfs_FindDevice +// yaffsfs_FindRoot +// Scan the configuration list to find the root. +static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath) +{ + yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList; + const char *leftOver; + const char *p; + + while(cfg && cfg->prefix && cfg->dev) + { + leftOver = path; + p = cfg->prefix; + while(*p && *leftOver && yaffsfs_Match(*p,*leftOver)) + { + p++; + leftOver++; + } + if(!*p) + { + // Matched prefix + *restOfPath = (char *)leftOver; + return cfg->dev; + } + cfg++; + } + return NULL; +} + +static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath) +{ + + yaffs_Device *dev; + + dev= yaffsfs_FindDevice(path,restOfPath); + if(dev && dev->isMounted) + { + return dev->rootDir; + } + return NULL; +} + +static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth) +{ + + while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + { + char *alias = obj->variant.symLinkVariant.alias; + + if(*alias == '/') + { + // Starts with a /, need to scan from root up + obj = yaffsfs_FindObject(NULL,alias,symDepth++); + } + else + { + // Relative to here, so use the parent of the symlink as a start + obj = yaffsfs_FindObject(obj->parent,alias,symDepth++); + } + } + return obj; +} + + +// yaffsfs_FindDirectory +// Parse a path to determine the directory and the name within the directory. +// +// eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx" +static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const char *path,char **name,int symDepth) +{ + yaffs_Object *dir; + char *restOfPath; + char str[YAFFS_MAX_NAME_LENGTH+1]; + int i; + + if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) + { + return NULL; + } + + if(startDir) + { + dir = startDir; + restOfPath = (char *)path; + } + else + { + dir = yaffsfs_FindRoot(path,&restOfPath); + } + + while(dir) + { + // parse off /. + // curve ball: also throw away surplus '/' + // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" + while(*restOfPath == '/') + { + restOfPath++; // get rid of '/' + } + + *name = restOfPath; + i = 0; + + while(*restOfPath && *restOfPath != '/') + { + if (i < YAFFS_MAX_NAME_LENGTH) + { + str[i] = *restOfPath; + str[i+1] = '\0'; + i++; + } + restOfPath++; + } + + if(!*restOfPath) + { + // got to the end of the string + return dir; + } + else + { + if(strcmp(str,".") == 0) + { + // Do nothing + } + else if(strcmp(str,"..") == 0) + { + dir = dir->parent; + } + else + { + dir = yaffs_FindObjectByName(dir,str); + + while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + { + + dir = yaffsfs_FollowLink(dir,symDepth); + + } + + if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + { + dir = NULL; + } + } + } + } + // directory did not exist. + return NULL; +} + +static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const char *path,char **name,int symDepth) +{ + return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth); +} + +// yaffsfs_FindObject turns a path for an existing object into the object +// +static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path,int symDepth) +{ + yaffs_Object *dir; + char *name; + + dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth); + + if(dir && *name) + { + return yaffs_FindObjectByName(dir,name); + } + + return dir; +} + + + +int yaffs_open(const char *path, int oflag, int mode) +{ + yaffs_Object *obj = NULL; + yaffs_Object *dir = NULL; + char *name; + int handle = -1; + yaffsfs_Handle *h = NULL; + int alreadyOpen = 0; + int alreadyExclusive = 0; + int openDenied = 0; + int symDepth = 0; + int errorReported = 0; + + int i; + + + // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR + + + yaffsfs_Lock(); + + handle = yaffsfs_GetHandle(); + + if(handle >= 0) + { + + h = yaffsfs_GetHandlePointer(handle); + + + // try to find the exisiting object + obj = yaffsfs_FindObject(NULL,path,0); + + if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + { + + obj = yaffsfs_FollowLink(obj,symDepth++); + } + + if(obj) + { + // Check if the object is already in use + alreadyOpen = alreadyExclusive = 0; + + for(i = 0; i <= YAFFSFS_N_HANDLES; i++) + { + + if(i != handle && + yaffsfs_handle[i].inUse && + obj == yaffsfs_handle[i].obj) + { + alreadyOpen = 1; + if(yaffsfs_handle[i].exclusive) + { + alreadyExclusive = 1; + } + } + } + + if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive) + { + openDenied = 1; + } + + // Open should fail if O_CREAT and O_EXCL are specified + if((oflag & O_EXCL) && (oflag & O_CREAT)) + { + openDenied = 1; + yaffsfs_SetError(-EEXIST); + errorReported = 1; + } + + // Check file permissions + if( (oflag & (O_RDWR | O_WRONLY)) == 0 && // ie O_RDONLY + !(obj->st_mode & S_IREAD)) + { + openDenied = 1; + } + + if( (oflag & O_RDWR) && + !(obj->st_mode & S_IREAD)) + { + openDenied = 1; + } + + if( (oflag & (O_RDWR | O_WRONLY)) && + !(obj->st_mode & S_IWRITE)) + { + openDenied = 1; + } + + } + + else if((oflag & O_CREAT)) + { + // Let's see if we can create this file + dir = yaffsfs_FindDirectory(NULL,path,&name,0); + if(dir) + { + obj = yaffs_MknodFile(dir,name,mode,0,0); + } + else + { + yaffsfs_SetError(-ENOTDIR); + } + } + + if(obj && !openDenied) + { + h->obj = obj; + h->inUse = 1; + h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1; + h->append = (oflag & O_APPEND) ? 1 : 0; + h->exclusive = (oflag & O_EXCL) ? 1 : 0; + h->position = 0; + + obj->inUse++; + if((oflag & O_TRUNC) && !h->readOnly) + { + //todo truncate + yaffs_ResizeFile(obj,0); + } + + } + else + { + yaffsfs_PutHandle(handle); + if(!errorReported) + { + yaffsfs_SetError(-EACCESS); + errorReported = 1; + } + handle = -1; + } + + } + + yaffsfs_Unlock(); + + return handle; +} + +int yaffs_close(int fd) +{ + yaffsfs_Handle *h = NULL; + int retVal = 0; + + yaffsfs_Lock(); + + h = yaffsfs_GetHandlePointer(fd); + + if(h && h->inUse) + { + // clean up + yaffs_FlushFile(h->obj,1); + h->obj->inUse--; + if(h->obj->inUse <= 0 && h->obj->unlinked) + { + yaffs_DeleteFile(h->obj); + } + yaffsfs_PutHandle(fd); + retVal = 0; + } + else + { + // bad handle + yaffsfs_SetError(-EBADF); + retVal = -1; + } + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_read(int fd, void *buf, unsigned int nbyte) +{ + yaffsfs_Handle *h = NULL; + yaffs_Object *obj = NULL; + int pos = 0; + int nRead = -1; + int maxRead; + + yaffsfs_Lock(); + h = yaffsfs_GetHandlePointer(fd); + obj = yaffsfs_GetHandleObject(fd); + + if(!h || !obj) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else if( h && obj) + { + pos= h->position; + if(yaffs_GetObjectFileLength(obj) > pos) + { + maxRead = yaffs_GetObjectFileLength(obj) - pos; + } + else + { + maxRead = 0; + } + + if(nbyte > maxRead) + { + nbyte = maxRead; + } + + + if(nbyte > 0) + { + nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte); + if(nRead >= 0) + { + h->position = pos + nRead; + } + else + { + //todo error + } + } + else + { + nRead = 0; + } + + } + + yaffsfs_Unlock(); + + + return (nRead >= 0) ? nRead : -1; + +} + +int yaffs_write(int fd, const void *buf, unsigned int nbyte) +{ + yaffsfs_Handle *h = NULL; + yaffs_Object *obj = NULL; + int pos = 0; + int nWritten = -1; + + yaffsfs_Lock(); + h = yaffsfs_GetHandlePointer(fd); + obj = yaffsfs_GetHandleObject(fd); + + if(!h || !obj) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else if( h && obj && h->readOnly) + { + // todo error + } + else if( h && obj) + { + if(h->append) + { + pos = yaffs_GetObjectFileLength(obj); + } + else + { + pos = h->position; + } + + nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte); + + if(nWritten >= 0) + { + h->position = pos + nWritten; + } + else + { + //todo error + } + + } + + yaffsfs_Unlock(); + + + return (nWritten >= 0) ? nWritten : -1; + +} + +int yaffs_truncate(int fd, unsigned int newSize) +{ + yaffsfs_Handle *h = NULL; + yaffs_Object *obj = NULL; + int result = 0; + + yaffsfs_Lock(); + h = yaffsfs_GetHandlePointer(fd); + obj = yaffsfs_GetHandleObject(fd); + + if(!h || !obj) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else + { + // resize the file + result = yaffs_ResizeFile(obj,newSize); + } + yaffsfs_Unlock(); + + + return (result) ? 0 : -1; + +} + +off_t yaffs_lseek(int fd, off_t offset, int whence) +{ + yaffsfs_Handle *h = NULL; + yaffs_Object *obj = NULL; + int pos = -1; + int fSize = -1; + + yaffsfs_Lock(); + h = yaffsfs_GetHandlePointer(fd); + obj = yaffsfs_GetHandleObject(fd); + + if(!h || !obj) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else if(whence == SEEK_SET) + { + if(offset >= 0) + { + pos = offset; + } + } + else if(whence == SEEK_CUR) + { + if( (h->position + offset) >= 0) + { + pos = (h->position + offset); + } + } + else if(whence == SEEK_END) + { + fSize = yaffs_GetObjectFileLength(obj); + if(fSize >= 0 && (fSize + offset) >= 0) + { + pos = fSize + offset; + } + } + + if(pos >= 0) + { + h->position = pos; + } + else + { + // todo error + } + + + yaffsfs_Unlock(); + + return pos; +} + + +int yaffsfs_DoUnlink(const char *path,int isDirectory) +{ + yaffs_Object *dir = NULL; + yaffs_Object *obj = NULL; + char *name; + int result = YAFFS_FAIL; + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL,path,0); + dir = yaffsfs_FindDirectory(NULL,path,&name,0); + if(!dir) + { + yaffsfs_SetError(-ENOTDIR); + } + else if(!obj) + { + yaffsfs_SetError(-ENOENT); + } + else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + yaffsfs_SetError(-EISDIR); + } + else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + { + yaffsfs_SetError(-ENOTDIR); + } + else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + { + yaffsfs_SetError(-ENOTDIR); + } + else + { + result = yaffs_Unlink(dir,name); + + if(result == YAFFS_FAIL && isDirectory) + { + yaffsfs_SetError(-ENOTEMPTY); + } + } + + yaffsfs_Unlock(); + + // todo error + + return (result == YAFFS_FAIL) ? -1 : 0; +} +int yaffs_rmdir(const char *path) +{ + return yaffsfs_DoUnlink(path,1); +} + +int yaffs_unlink(const char *path) +{ + return yaffsfs_DoUnlink(path,0); +} + +int yaffs_rename(const char *oldPath, const char *newPath) +{ + yaffs_Object *olddir = NULL; + yaffs_Object *newdir = NULL; + yaffs_Object *obj = NULL; + char *oldname; + char *newname; + int result= YAFFS_FAIL; + int renameAllowed = 1; + + yaffsfs_Lock(); + + olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0); + newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0); + obj = yaffsfs_FindObject(NULL,oldPath,0); + + if(!olddir || !newdir || !obj) + { + // bad file + yaffsfs_SetError(-EBADF); + renameAllowed = 0; + } + else if(olddir->myDev != newdir->myDev) + { + // oops must be on same device + // todo error + yaffsfs_SetError(-EXDEV); + renameAllowed = 0; + } + else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + // It is a directory, check that it is not being renamed to + // being its own decendent. + // Do this by tracing from the new directory back to the root, checking for obj + + yaffs_Object *xx = newdir; + + while( renameAllowed && xx) + { + if(xx == obj) + { + renameAllowed = 0; + } + xx = xx->parent; + } + if(!renameAllowed) yaffsfs_SetError(-EACCESS); + } + + if(renameAllowed) + { + result = yaffs_RenameObject(olddir,oldname,newdir,newname); + } + + yaffsfs_Unlock(); + + return (result == YAFFS_FAIL) ? -1 : 0; +} + + +static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf) +{ + int retVal = -1; + + if(obj) + { + obj = yaffs_GetEquivalentObject(obj); + } + + if(obj && buf) + { + buf->st_dev = (int)obj->myDev->genericDevice; + buf->st_ino = obj->objectId; + buf->st_mode = obj->st_mode & ~S_IFMT; // clear out file type bits + + if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + buf->st_mode |= S_IFDIR; + } + else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + { + buf->st_mode |= S_IFLNK; + } + else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) + { + buf->st_mode |= S_IFREG; + } + + buf->st_nlink = yaffs_GetObjectLinkCount(obj); + buf->st_uid = 0; + buf->st_gid = 0;; + buf->st_rdev = obj->st_rdev; + buf->st_size = yaffs_GetObjectFileLength(obj); + buf->st_blksize = obj->myDev->nBytesPerChunk; + buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize; + buf->st_atime = obj->st_atime; + buf->st_ctime = obj->st_ctime; + buf->st_mtime = obj->st_mtime; + retVal = 0; + } + return retVal; +} + +static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int doLStat) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_FindObject(NULL,path,0); + + if(!doLStat && obj) + { + obj = yaffsfs_FollowLink(obj,0); + } + + if(obj) + { + retVal = yaffsfs_DoStat(obj,buf); + } + else + { + // todo error not found + yaffsfs_SetError(-ENOENT); + } + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_stat(const char *path, struct yaffs_stat *buf) +{ + return yaffsfs_DoStatOrLStat(path,buf,0); +} + +int yaffs_lstat(const char *path, struct yaffs_stat *buf) +{ + return yaffsfs_DoStatOrLStat(path,buf,1); +} + +int yaffs_fstat(int fd, struct yaffs_stat *buf) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_GetHandleObject(fd); + + if(obj) + { + retVal = yaffsfs_DoStat(obj,buf); + } + else + { + // bad handle + yaffsfs_SetError(-EBADF); + } + + yaffsfs_Unlock(); + + return retVal; +} + +static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode) +{ + int result; + + if(obj) + { + obj = yaffs_GetEquivalentObject(obj); + } + + if(obj) + { + obj->st_mode = mode; + obj->dirty = 1; + result = yaffs_FlushFile(obj,0); + } + + return result == YAFFS_OK ? 0 : -1; +} + + +int yaffs_chmod(const char *path, mode_t mode) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_FindObject(NULL,path,0); + + if(obj) + { + retVal = yaffsfs_DoChMod(obj,mode); + } + else + { + // todo error not found + yaffsfs_SetError(-ENOENT); + } + + yaffsfs_Unlock(); + + return retVal; + +} + + +int yaffs_fchmod(int fd, mode_t mode) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_GetHandleObject(fd); + + if(obj) + { + retVal = yaffsfs_DoChMod(obj,mode); + } + else + { + // bad handle + yaffsfs_SetError(-EBADF); + } + + yaffsfs_Unlock(); + + return retVal; +} + + +int yaffs_mkdir(const char *path, mode_t mode) +{ + yaffs_Object *parent = NULL; + yaffs_Object *dir; + char *name; + int retVal= -1; + + yaffsfs_Lock(); + parent = yaffsfs_FindDirectory(NULL,path,&name,0); + dir = yaffs_MknodDirectory(parent,name,mode,0,0); + if(dir) + { + retVal = 0; + } + else + { + yaffsfs_SetError(-ENOSPC); // just assume no space for now + retVal = -1; + } + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_mount(const char *path) +{ + int retVal=-1; + int result=YAFFS_FAIL; + yaffs_Device *dev=NULL; + char *dummy; + + T(YAFFS_TRACE_ALWAYS,("yaffs: Mounting %s\n",path)); + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path,&dummy); + if(dev) + { + if(!dev->isMounted) + { + result = yaffs_GutsInitialise(dev); + if(result == YAFFS_FAIL) + { + // todo error - mount failed + yaffsfs_SetError(-ENOMEM); + } + retVal = result ? 0 : -1; + + } + else + { + //todo error - already mounted. + yaffsfs_SetError(-EBUSY); + } + } + else + { + // todo error - no device + yaffsfs_SetError(-ENODEV); + } + yaffsfs_Unlock(); + return retVal; + +} + +int yaffs_unmount(const char *path) +{ + int retVal=-1; + yaffs_Device *dev=NULL; + char *dummy; + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path,&dummy); + if(dev) + { + if(dev->isMounted) + { + int i; + int inUse; + for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++) + { + if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev) + { + inUse = 1; // the device is in use, can't unmount + } + } + + if(!inUse) + { + yaffs_Deinitialise(dev); + + retVal = 0; + } + else + { + // todo error can't unmount as files are open + yaffsfs_SetError(-EBUSY); + } + + } + else + { + //todo error - not mounted. + yaffsfs_SetError(-EINVAL); + + } + } + else + { + // todo error - no device + yaffsfs_SetError(-ENODEV); + } + yaffsfs_Unlock(); + return retVal; + +} + +off_t yaffs_freespace(const char *path) +{ + off_t retVal=-1; + yaffs_Device *dev=NULL; + char *dummy; + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path,&dummy); + if(dev) + { + retVal = yaffs_GetNumberOfFreeChunks(dev); + retVal *= dev->nBytesPerChunk; + + } + else + { + yaffsfs_SetError(-EINVAL); + } + + yaffsfs_Unlock(); + return retVal; +} + +void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList) +{ + + yaffsfs_DeviceConfiguration *cfg; + + yaffsfs_configurationList = cfgList; + + yaffsfs_InitHandles(); + + cfg = yaffsfs_configurationList; + + while(cfg && cfg->prefix && cfg->dev) + { + cfg->dev->isMounted = 0; + cfg++; + } + + +} + + +// +// Directory search stuff. + +yaffs_DIR *yaffs_opendir(const char *dirname) +{ + yaffs_DIR *dir = NULL; + yaffs_Object *obj = NULL; + yaffsfs_DirectorySearchContext *dsc = NULL; + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL,dirname,0); + + if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + + dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext)); + dir = (yaffs_DIR *)dsc; + if(dsc) + { + dsc->magic = YAFFS_MAGIC; + dsc->list = NULL; + memset(dsc->name,0,NAME_MAX+1); + strncpy(dsc->name,dirname,NAME_MAX); + } + + } + + yaffsfs_Unlock(); + + return dir; +} + +struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) +{ + yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; + struct yaffs_dirent *retVal = NULL; + struct list_head *i; + yaffs_Object *entry = NULL; + int offset; + yaffs_Object *obj = NULL; + struct yaffsfs_ObjectListEntry *list = NULL; + int inList = 0; + + yaffsfs_Lock(); + + offset = -1; + + if(dsc && dsc->magic == YAFFS_MAGIC) + { + yaffsfs_SetError(0); + + obj = yaffsfs_FindObject(NULL,dsc->name,0); + + if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + + list_for_each(i,&obj->variant.directoryVariant.children) + { + offset++; + entry = (i) ? list_entry(i, yaffs_Object,siblings) : NULL; + + if(entry) + { + list = dsc->list; + inList = 0; + while(list && !inList) + { + if(list->objectId == entry->objectId) + { + inList = 1; + } + list = list->next; + } + + if(!inList) goto foundNew; + } + + } + + foundNew: + + if(!inList && entry) + { + //This is the entry we're going to return; + struct yaffsfs_ObjectListEntry *le; + + le = YMALLOC(sizeof(struct yaffsfs_ObjectListEntry)); + + if(le) + { + le->next = dsc->list; + le->objectId = entry->objectId; + dsc->list = le; + + dsc->de.d_ino = yaffs_GetEquivalentObject(entry)->objectId; + dsc->de.d_off = offset; + yaffs_GetObjectName(entry,dsc->de.d_name,NAME_MAX+1); + dsc->de.d_reclen = sizeof(struct yaffs_dirent); + + retVal = &dsc->de; + } + + } + } + + } + else + { + yaffsfs_SetError(-EBADF); + } + + yaffsfs_Unlock(); + + return retVal; + +} + +void yaffsfs_ListClear(yaffsfs_DirectorySearchContext *dsc) +{ + + struct yaffsfs_ObjectListEntry *le; + + if(dsc && dsc->magic == YAFFS_MAGIC) + { + while(dsc->list) + { + le = dsc->list; + dsc->list = dsc->list->next; + YFREE(le); + } + } + +} + +void yaffs_rewinddir(yaffs_DIR *dirp) +{ + yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; + + yaffsfs_Lock(); + yaffsfs_ListClear(dsc); + yaffsfs_Unlock(); +} + + +int yaffs_closedir(yaffs_DIR *dirp) +{ + yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; + + yaffsfs_Lock(); + yaffsfs_ListClear(dsc); + dsc->magic = 0; + YFREE(dsc); + yaffsfs_Unlock(); + return 0; +} + + + +int yaffs_symlink(const char *oldpath, const char *newpath) +{ + yaffs_Object *parent = NULL; + yaffs_Object *obj; + char *name; + int retVal= -1; + int mode = 0; // ignore for now + + yaffsfs_Lock(); + parent = yaffsfs_FindDirectory(NULL,newpath,&name,0); + obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath); + if(obj) + { + retVal = 0; + } + else + { + yaffsfs_SetError(-ENOSPC); // just assume no space for now + retVal = -1; + } + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_readlink(const char *path, char *buf, int bufsiz) +{ + yaffs_Object *obj = NULL; + int retVal; + + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL,path,0); + + if(!obj) + { + yaffsfs_SetError(-ENOENT); + retVal = -1; + } + else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK) + { + yaffsfs_SetError(-EINVAL); + retVal = -1; + } + else + { + char *alias = obj->variant.symLinkVariant.alias; + memset(buf,0,bufsiz); + strncpy(buf,alias,bufsiz - 1); + retVal = 0; + } + yaffsfs_Unlock(); + return retVal; +} + +int yaffs_link(const char *oldpath, const char *newpath); +int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev); + +int yaffs_DumpDevStruct(const char *path) +{ + char *rest; + + yaffs_Object *obj = yaffsfs_FindRoot(path,&rest); + + if(obj) + { + yaffs_Device *dev = obj->myDev; + + printf("\n" + "nPageWrites.......... %d\n" + "nPageReads........... %d\n" + "nBlockErasures....... %d\n" + "nGCCopies............ %d\n" + "garbageCollections... %d\n" + "passiveGarbageColl'ns %d\n" + "\n", + dev->nPageWrites, + dev->nPageReads, + dev->nBlockErasures, + dev->nGCCopies, + dev->garbageCollections, + dev->passiveGarbageCollections + ); + + } + return 0; +} + diff --git a/direct/yaffsfs.h b/direct/yaffsfs.h new file mode 100644 index 0000000..2f99474 --- /dev/null +++ b/direct/yaffsfs.h @@ -0,0 +1,216 @@ +/* +* Header file for using yaffs in an application via +* a direct interface. +*/ + + +#ifndef __YAFFSFS_H__ +#define __YAFFSFS_H__ + +#include "yaffscfg.h" +#include "yportenv.h" + + +//typedef long off_t; +//typedef long dev_t; +//typedef unsigned long mode_t; + + +#ifndef NAME_MAX +#define NAME_MAX 256 +#endif + +#ifndef O_RDONLY +#define O_RDONLY 00 +#endif + +#ifndef O_WRONLY +#define O_WRONLY 01 +#endif + +#ifndef O_RDWR +#define O_RDWR 02 +#endif + +#ifndef O_CREAT +#define O_CREAT 0100 +#endif + +#ifndef O_EXCL +#define O_EXCL 0200 +#endif + +#ifndef O_TRUNC +#define O_TRUNC 01000 +#endif + +#ifndef O_APPEND +#define O_APPEND 02000 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef EBUSY +#define EBUSY 16 +#endif + +#ifndef ENODEV +#define ENODEV 19 +#endif + +#ifndef EINVAL +#define EINVAL 22 +#endif + +#ifndef EBADF +#define EBADF 9 +#endif + +#ifndef EACCESS +#define EACCESS 13 +#endif + +#ifndef EXDEV +#define EXDEV 18 +#endif + +#ifndef ENOENT +#define ENOENT 2 +#endif + +#ifndef ENOSPC +#define ENOSPC 28 +#endif + +#ifndef ENOTEMPTY +#define ENOTEMPTY 39 +#endif + +#ifndef ENOMEM +#define ENOMEM 12 +#endif + +#ifndef EEXIST +#define EEXIST 17 +#endif + +#ifndef ENOTDIR +#define ENOTDIR 20 +#endif + +#ifndef EISDIR +#define EISDIR 21 +#endif + + +// Mode flags + +#ifndef S_IFMT +#define S_IFMT 0170000 +#endif + +#ifndef S_IFLNK +#define S_IFLNK 0120000 +#endif + +#ifndef S_IFDIR +#define S_IFDIR 0040000 +#endif + +#ifndef S_IFREG +#define S_IFREG 0100000 +#endif + +#ifndef S_IREAD +#define S_READ 0000400 +#endif + +#ifndef S_IWRITE +#define S_IWRITE 0000200 +#endif + + + + +struct yaffs_dirent{ + long d_ino; /* inode number */ + off_t d_off; /* offset to this dirent */ + unsigned short d_reclen; /* length of this d_name */ + char d_name [NAME_MAX+1]; /* file name (null-terminated) */ +}; + +typedef struct yaffs_dirent yaffs_dirent; + + +typedef struct __opaque yaffs_DIR; + + +struct yaffs_stat{ + int st_dev; /* device */ + int st_ino; /* inode */ + mode_t st_mode; /* protection */ + int st_nlink; /* number of hard links */ + int st_uid; /* user ID of owner */ + int st_gid; /* group ID of owner */ + unsigned st_rdev; /* device type (if inode device) */ + off_t st_size; /* total size, in bytes */ + unsigned long st_blksize; /* blocksize for filesystem I/O */ + unsigned long st_blocks; /* number of blocks allocated */ + unsigned long st_atime; /* time of last access */ + unsigned long st_mtime; /* time of last modification */ + unsigned long st_ctime; /* time of last change */ +}; + +int yaffs_open(const char *path, int oflag, int mode) ; +int yaffs_read(int fd, void *buf, unsigned int nbyte) ; +int yaffs_write(int fd, const void *buf, unsigned int nbyte) ; +int yaffs_close(int fd) ; +off_t yaffs_lseek(int fd, off_t offset, int whence) ; +int yaffs_truncate(int fd, unsigned int newSize); + +int yaffs_unlink(const char *path) ; +int yaffs_rename(const char *oldPath, const char *newPath) ; + +int yaffs_stat(const char *path, struct yaffs_stat *buf) ; +int yaffs_lstat(const char *path, struct yaffs_stat *buf) ; +int yaffs_fstat(int fd, struct yaffs_stat *buf) ; + +int yaffs_chmod(const char *path, mode_t mode); +int yaffs_fchmod(int fd, mode_t mode); + +int yaffs_mkdir(const char *path, mode_t mode) ; +int yaffs_rmdir(const char *path) ; + +yaffs_DIR *yaffs_opendir(const char *dirname) ; +struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ; +void yaffs_rewinddir(yaffs_DIR *dirp) ; +int yaffs_closedir(yaffs_DIR *dirp) ; + +int yaffs_mount(const char *path) ; +int yaffs_unmount(const char *path) ; + +int yaffs_symlink(const char *oldpath, const char *newpath); +int yaffs_readlink(const char *path, char *buf, int bufsiz); + +int yaffs_link(const char *oldpath, const char *newpath); +int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev); + +off_t yaffs_freespace(const char *path); + +void yaffs_initialise(yaffsfs_DeviceConfiguration *configList); + +int yaffs_StartUp(void); + +#endif + + -- 2.30.2