From: charles Date: Tue, 21 Jan 2003 03:32:17 +0000 (+0000) Subject: *** empty log message *** X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs%2F.git;a=commitdiff_plain;h=4ea0578f8af411adf56fdc1eb4af08f4e36c7eec *** empty log message *** --- diff --git a/Documentation/yaffs_boot.html b/Documentation/yaffs_boot.html new file mode 100644 index 0000000..6591a55 --- /dev/null +++ b/Documentation/yaffs_boot.html @@ -0,0 +1,58 @@ + + + + + + + + + + + + +

Example YAFFS Bootloader

+

Licensing

+

The YAFFS bootloader is LGPL to facilitate integration into +non-GPL code.

+

Software Modules

+

The software is designed in a modular fashion to facilitate +integration and configuration.

+

The software comprises the following main sections:

+ + +

The bootloader does not implement YAFFS. Instead it is a simple +set of routines which allows reading a file on a YAFFS device.

+

The file must be in the root directory of the device (eg. +"/boot/boot.bin") since the bootloader does not understand +directories. This limitation simplifies the bootloader and speeds up +the boot process.

+

As shown here the bootloader is initialised, then provides the +boot file as a stream of bytes. It is simple enough to provide the +data in other formats.

+

$Id: yaffs_boot.html,v 1.1 2003-01-21 03:34:12 charles Exp $

+



+

+



+

+



+

+



+

+



+

+



+

+



+

+



+

+ + \ No newline at end of file diff --git a/Documentation/yaffs_direct.html b/Documentation/yaffs_direct.html new file mode 100644 index 0000000..6683054 --- /dev/null +++ b/Documentation/yaffs_direct.html @@ -0,0 +1,160 @@ + + + + + + + + + + + + +

YAFFS Direct Interface (YDI)

+

Now hear this!

+

YAFFS code is GPL. The YAFFS Direct Interface(YDI) is really +intended to provide a direct interface to YAFFS in an embedded/RTOS +environment. Using YAFFS in this way might violate GPL. Aleph One are +looking at ways to make YAFFS licensing more flexible to support both +GPL and YDI users. For further info, please contact Aleph One.

+

Purpose

+

The purpose of the YAFFS Direct Interface is to provide YAFFS to +embedded/RTOS environments where full file system support is not +available. Typically, therefore, YDI is intended for smaller embedded +systems.

+

Software Modules

+

The software is designed in a modular fashion to facilitate +integration and configuration.

+

The software comprises the following main sections:

+ +



+

+

General Notes

+

Licensing

+

The YAFFS file system is GPL.

+

The YAFFS bootloader and header files are LGPL to allow +incorporation of these into proprietary code.

+

nand_ecc.c, copyright SJ Hill, is LGPL.

+

File names

+

Multiple partitions are defined by setting up the partition table +in yaffscfg.c.

+

The system has no concept of current directory, therefore all +names and paths must be fully specified. eg. "/boot/xxx"

+

Names are case sensitive. +

+

The divider between path elements is '/'. eg "/ram/dir/file".

+

Permissions and attributes

+

The following permissions are supported in mode: S_IREAD, +S_IWRITE.

+

The following opening modes are checked: O_RDONLY, O_WRONLY, +O_RDWR, O_EXCL.

+

Times are just flat 32-bit numbers. The meaning of these numbers +is OS dependent and is defined by completing the funbctiuon +yaffsfs_CurrentTime() in yaffscfg.c

+

Attributes are stored as a 32-bit unsigned value. Some of these +are reserved. Others are used transparently (and may be used for +additional information by the application). Reserved are:

+ +



+

+

Threading

+

All yaffs routines are thread safe when called through the +specified interface.

+

All yaffs routines are controlled by a single locking +mutex/semaphore by defining yaffsfs_Lock() and yaffsfs_Unlock() in +yaffscfg.c. +

+

Thus, only one thread is able to execute yaffs functions at a +time. Most yaffs functions execute quickly, so this generally not a +limitation.

+

Compilation Configuration

+

Configuration is done in four places: +

+ +

Device Configuration

+

The device configuration table is set up in yaffscfg.c and +specifies what devices are in the system. The order is important +since this is the order that is used when searching for +files/directories and provides the "switch" mechanism to +support multiple "mount points"

+

The device configuration has the form:

+

struct { +
const char *prefix;
yaffs_Device *dev;
};

+

eg.

+

{
{"/ram",ramDevice}, +
{"/boot",bootDevice},
{"/flash",flashDevice},
{NULL,NULL}
}

+

Note that multiple yaffs_Devices can share a single physical NAND +device by "partitioning". Thus, for instance, /boot and +/data may be on the same physical device, just with non-overlapping +regions.

+

Different properties may be attached to the different yaffs_Device +entries. For example note that the RAM disk is set up with different +NANDECC flags.

+

API Notes

+

int yaffs_open(const char *path, int oflag, int mode) ;

+

Supported flags O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_RDONLY, +O_RDWR, O_WRONLY.

+

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_unlink(const char *path) ;

+

int yaffs_rename(const char *old, const char *new) ;

+

int yaffs_stat(const char *path, struct stat *buf) ;

+

int yaffs_lstat(const char *path, struct stat *buf) ;

+

int yaffs_fstat(int fd, struct, struct stat *buf) ;

+

int yaffs_chmod(const char *path, mode_t mode) ;

+

int yaffs_fchmod(int fd, struct, 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, size_t 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);

+



+

+

$Id: yaffs_direct.html,v 1.1 2003-01-21 03:34:12 charles Exp $

+



+

+ + \ No newline at end of file diff --git a/direct/Makefile b/direct/Makefile new file mode 100644 index 0000000..22a18cd --- /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 2003-01-21 03:32:17 charles Exp $ + +CFLAGS = -Wall -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -g +#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations +#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline + + +DIRECTTESTOBJS = dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o yaffs_guts.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 nand_ecc.c yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.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/bootldtst.c b/direct/bootldtst.c new file mode 100644 index 0000000..bbb0aec --- /dev/null +++ b/direct/bootldtst.c @@ -0,0 +1,73 @@ + + +#include + +#include "yaffs_guts.h" +#include "yaffs_flashif.h" + +#include "yboot.h" + + +unsigned yaffs_traceMask = 0xFFFFFFFF; + +static void InitDevice(yaffs_Device *dev) +{ + // Initialise the NAND device. This should agree with what is set in yaffscfg for /boot + + // /boot + // Only some of these parameters are actually used. + dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK; + dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; + dev->startBlock = 1; // Can't use block 0 + dev->endBlock = 127; // Last block in 2MB. + dev->useNANDECC = 0; // use YAFFS's ECC + dev->nShortOpCaches = 10; // Use caches + dev->genericDevice = (void *) 1; // Used to identify the device in fstat. + dev->writeChunkToNAND = yflash_WriteChunkToNAND; + dev->readChunkFromNAND = yflash_ReadChunkFromNAND; + dev->eraseBlockInNAND = yflash_EraseBlockInNAND; + dev->initialiseNAND = yflash_InitialiseNAND; +} + + +int main() +{ + int oId; + + char ch; + int nBytes = 0; + int fsize; + + yaffs_Device dev; + + printf("Test boot code\n"); + + InitDevice(&dev); + + oId = yaffsboot_InitFile(&dev,"yyfile",&fsize); + + printf("ObjectId = %d, size is %d\n",oId,fsize); + + if(oId < 0) + { + printf("File not found\n"); + } + else + { + printf("dumping file as text\n\n"); + + nBytes = 0; + + while(yaffsboot_ReadByte(&ch) >= 0) + { + printf("%c",ch); + nBytes++; + } + + printf("\n\n%d bytes read\n",nBytes); + } + + + + +} diff --git a/direct/dtest.c b/direct/dtest.c new file mode 100644 index 0000000..7360584 --- /dev/null +++ b/direct/dtest.c @@ -0,0 +1,409 @@ +/* +* Test code for the "direct" interface. +*/ + + +#include +#include + +#include "yaffsfs.h" + +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 fill_disk(char *path,int nfiles) +{ + int h; + int n; + int result; + + 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) + { + //printf("."); + } + 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 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,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,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,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,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 main(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"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + f = yaffs_open("/boot/b1", O_RDONLY,0); + + printf("open /boot/b1 readonly, f=%d\n",f); + + f = yaffs_open("/boot/b1", O_CREAT,0); + + 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,SEEK_END,0); + 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,SEEK_SET,0); + 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); + + + 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",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"); + + + return 0; + +} diff --git a/direct/yaffs_fileem.c b/direct/yaffs_fileem.c new file mode 100644 index 0000000..ccb88fa --- /dev/null +++ b/direct/yaffs_fileem.c @@ -0,0 +1,216 @@ +/* + * 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 2003-01-21 03:32:17 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, 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_flashif.c b/direct/yaffs_flashif.c new file mode 100644 index 0000000..98e6df2 --- /dev/null +++ b/direct/yaffs_flashif.c @@ -0,0 +1,227 @@ +/* + * 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 2003-01-21 03:32:17 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(spare) + { + memcpy(&ramdisk.block[blk]->page[pg].data[512],spare,16); + } + + return YAFFS_OK; + +} + + +int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare) +{ + int blk; + int pg; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + if(data) + { + memcpy(data,ramdisk.block[blk]->page[pg].data,512); + } + + + if(spare) + { + memcpy(spare,&ramdisk.block[blk]->page[pg].data[512],16); + if(dev->useNANDECC) + { + struct yaffs_NANDSpare *nsp = (struct yaffs_NANDSpare *)spare; + nsp->eccres1 = 0; + nsp->eccres2 = 0; + } + } + + 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_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_flashif.h b/direct/yaffs_flashif.h new file mode 100644 index 0000000..561dc72 --- /dev/null +++ b/direct/yaffs_flashif.h @@ -0,0 +1,31 @@ +/* + * 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 2003-01-21 03:32:17 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, yaffs_Spare *spare); +int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare); +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yflash_InitialiseNAND(yaffs_Device *dev); + +#endif diff --git a/direct/yaffs_ramdisk.c b/direct/yaffs_ramdisk.c new file mode 100644 index 0000000..90a37d0 --- /dev/null +++ b/direct/yaffs_ramdisk.c @@ -0,0 +1,227 @@ +/* + * 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 2003-01-21 03:32:17 charles Exp $"; + + +#include "yportenv.h" + +#include "yaffs_ramdisk.h" +#include "yaffs_guts.h" +#include "devextras.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(spare) + { + memcpy(&ramdisk.block[blk]->page[pg].data[512],spare,16); + } + + return YAFFS_OK; + +} + + +int yramdisk_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare) +{ + int blk; + int pg; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + if(data) + { + memcpy(data,ramdisk.block[blk]->page[pg].data,512); + } + + + if(spare) + { + memcpy(spare,&ramdisk.block[blk]->page[pg].data[512],16); + if(dev->useNANDECC) + { + struct yaffs_NANDSpare *nsp = (struct yaffs_NANDSpare *)spare; + nsp->eccres1 = 0; + nsp->eccres2 = 0; + } + } + + 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..a4f3b2c --- /dev/null +++ b/direct/yaffs_ramdisk.h @@ -0,0 +1,31 @@ +/* + * 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 2003-01-21 03:32:17 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_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_Spare *spare); +int yramdisk_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare); +int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yramdisk_InitialiseNAND(yaffs_Device *dev); + +#endif diff --git a/direct/yaffscfg.c b/direct/yaffscfg.c new file mode 100644 index 0000000..1b9576a --- /dev/null +++ b/direct/yaffscfg.c @@ -0,0 +1,119 @@ +/* + * 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 = YAFFS_BYTES_PER_CHUNK; + ramDev.nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; + 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.writeChunkToNAND = yramdisk_WriteChunkToNAND; + ramDev.readChunkFromNAND = yramdisk_ReadChunkFromNAND; + ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND; + ramDev.initialiseNAND = yramdisk_InitialiseNAND; + + // /boot + bootDev.nBytesPerChunk = YAFFS_BYTES_PER_CHUNK; + bootDev.nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; + 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 = YAFFS_BYTES_PER_CHUNK; + flashDev.nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; + 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..b8a53b3 --- /dev/null +++ b/direct/yaffscfg.h @@ -0,0 +1,31 @@ +/* +* Header file for using yaffs in an application via +* a direct interface. +*/ + + +#ifndef __YAFFSCFG_H__ +#define __YAFFSCFG_H__ + + + +#include "yaffs_guts.h" + +#define YAFFSFS_N_HANDLES 200 + + +typedef struct { + const char *prefix; + yaffs_Device *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/yaffsfs.c b/direct/yaffsfs.c new file mode 100644 index 0000000..d3eae30 --- /dev/null +++ b/direct/yaffsfs.c @@ -0,0 +1,1337 @@ +/* + * 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 2003-01-21 03:32:17 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 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; + } + + // 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); + obj = yaffs_MknodFile(dir,name,mode,0,0); + } + + 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); + yaffsfs_SetError(-EACCESS); + 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 + { + //todo error + } + + } + + 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; + +} + +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; + char *oldname; + char *newname; + int result= YAFFS_FAIL; + + yaffsfs_Lock(); + + olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0); + newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0); + + if(!olddir || !newdir) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else if(olddir->myDev != newdir->myDev) + { + // oops must be on same device + // todo error + yaffsfs_SetError(-EXDEV); + } + else + { + 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 = YAFFS_BYTES_PER_CHUNK; + buf->st_blocks = (buf->st_size + YAFFS_BYTES_PER_CHUNK -1)/YAFFS_BYTES_PER_CHUNK; + 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; + + 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 *= YAFFS_BYTES_PER_CHUNK; + + } + 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 + ); + } +} + diff --git a/direct/yaffsfs.h b/direct/yaffsfs.h new file mode 100644 index 0000000..36dc906 --- /dev/null +++ b/direct/yaffsfs.h @@ -0,0 +1,211 @@ +/* +* 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 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_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 + + diff --git a/direct/yboot.c b/direct/yboot.c new file mode 100644 index 0000000..cd4b906 --- /dev/null +++ b/direct/yboot.c @@ -0,0 +1,290 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yboot: A yaffs bootloader. + * + * 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 +#include +#include "yaffs_guts.h" + +const char *yboot_c_version="$Id: yboot.c,v 1.1 2003-01-21 03:32:17 charles Exp $"; + + +#define MAX_FILE_SIZE 4000000 +#define MAX_CHUNKS (MAX_FILE_SIZE/YAFFS_BYTES_PER_CHUNK + 1) + +static int chunkLocations[MAX_CHUNKS]; + + +// External functions for ECC on data +void nand_calculate_ecc (const unsigned char*dat, unsigned char*ecc_code); +int nand_correct_data (unsigned char*dat, unsigned char*read_ecc, unsigned char*calc_ecc); + +static const char yaffs_countBits[256] = +{ +0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4, +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, +4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 +}; + + +static void spareToTags(yaffs_Spare *spare, yaffs_Tags *tag) +{ + unsigned char *bytes = (char *)tag; + bytes[0] = spare->tagByte0; + bytes[1] = spare->tagByte1; + bytes[2] = spare->tagByte2; + bytes[3] = spare->tagByte3; + bytes[4] = spare->tagByte4; + bytes[5] = spare->tagByte5; + bytes[6] = spare->tagByte6; + bytes[7] = spare->tagByte7; +} + + + +// yboot_ScanForFile finds +static int yaffsboot_ScanForFile(yaffs_Device *dev, const char *fileName) +{ + int pg; + int blk; + yaffs_ObjectHeader data; + yaffs_Spare spare; + yaffs_Tags tags; + + + if (!fileName) + { + //printf("NULL filename\n"); + return -1; + } + + + + //printf("Searching block range %d to %d for %s\n", dev->startBlock, dev->endBlock, fileName); + + for (blk = dev->startBlock; blk < dev->endBlock; blk++) + { + + for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++) + { + dev->readChunkFromNAND(dev, (blk*YAFFS_CHUNKS_PER_BLOCK) + pg, (__u8 *)&data, (yaffs_Spare *)&spare); + if (yaffs_countBits[spare.blockStatus] >=7 && // block OK + yaffs_countBits[spare.pageStatus] >= 7) // page ok + { + spareToTags(&spare, &tags); + + if ( tags.chunkId == 0 && // it's a header + data.parentObjectId == YAFFS_OBJECTID_ROOT && // it's in the root + strcmp(data.name, fileName) == 0 // name matches + ) + { + //printf("%s found at chunk %x objectId is %x\n", fileName, blk* YAFFS_PAGES_PER_BLOCK + pg, tag.objectId); + + return tags.objectId; + } + } + } + } + // Sad day... not found. + // printf("%s not found\n",filename); + return -1; +} + + + +static unsigned char bufferData[YAFFS_BYTES_PER_CHUNK]; +static int bufferPos = 0; +static int bufferChunk = 0; +static int bufferInitialised = 0; +static int bufferLength = 0; + +static yaffs_Device *bufferDevice; + +static int chunkEnd = -1; +static int topChunk = -1; +static int fileSize = -1; + +int yaffsboot_InitFile(yaffs_Device *dev, const char *fileName,int *loadedFileSize) +{ + + yaffs_Spare spare; + yaffs_Tags tags; + int fileObjId; + int i; + + int blk; + int pg; + int missing; + int chunksMissing = 0; + + bufferDevice = dev; + + fileObjId = yaffsboot_ScanForFile(dev,fileName); + + if(fileObjId < 0) + { + return -1; + } + + + + //printf("Gathering chunks...\n"); + + for (i = 0; i < MAX_CHUNKS; i++) + { + chunkLocations[i] = -1; + } + + + for (blk = dev->startBlock; blk <= dev->endBlock; blk++) + { + for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++) + { + dev->readChunkFromNAND(dev, blk * YAFFS_CHUNKS_PER_BLOCK + pg, NULL, &spare); + if (yaffs_countBits[spare.blockStatus] >= 7 && + yaffs_countBits[spare.pageStatus] >= 7) + { + spareToTags(&spare, &tags); + + if (tags.objectId == fileObjId && tags.chunkId > 0) + { + + if(tags.chunkId >= MAX_CHUNKS) + { + printf("Chunk %d out of bounds (max is %d)\n",tags.chunkId, MAX_CHUNKS - 1); + return -1; + } + + chunkLocations[tags.chunkId] = (blk*32) + pg; + + chunkEnd = (tags.chunkId -1) * YAFFS_BYTES_PER_CHUNK + tags.byteCount; + + if(chunkEnd > fileSize) fileSize = chunkEnd; + + if(tags.chunkId > topChunk) topChunk = tags.chunkId; + } + } + } + } + + + for (missing= 0, i= 1; i<= topChunk; i++) + { + if (chunkLocations[i] < 0) + { + //printf("chunk %x missing\n",i); + chunksMissing++; + } + } + + *loadedFileSize = fileSize; + + return fileObjId; +} + + + +int yaffsboot_Reinitialise(void) +{ + bufferInitialised = 0; + return 0; +} + + +int yaffsboot_ReadByte(unsigned char *bPtr) +{ + if(!bufferInitialised) + { + //printf("Read buffer initialisation\n"); + bufferInitialised = 1; + bufferChunk = 0; + bufferLength = 0; + bufferPos = -1; + } + + if(bufferPos < 0) + { + bufferChunk++; + if(bufferChunk> topChunk) + { + printf("Chunk %d past end of file\r\n",bufferChunk); + + return -1; + } + + if (chunkLocations[bufferChunk] < 0) + { + printf("No chunk %d, zero page\n",bufferChunk); + memset(bufferData,0,YAFFS_BYTES_PER_CHUNK); + bufferLength = YAFFS_BYTES_PER_CHUNK; + } + else + { + yaffs_Spare localSpare; + yaffs_Tags tags; + __u8 calcEcc[3]; + + bufferDevice->readChunkFromNAND(bufferDevice, chunkLocations[bufferChunk], bufferData, &localSpare); + + spareToTags(&localSpare, &tags); + + if(0 && bufferChunk = bufferLength) + { + //printf("End of page %d at byte %d\r\n",bufferChunk,bufferLength); + bufferPos = -1; + } + return 0; +} + + + + diff --git a/direct/yboot.h b/direct/yboot.h new file mode 100644 index 0000000..63dc7f8 --- /dev/null +++ b/direct/yboot.h @@ -0,0 +1,28 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yboot.h: Interface to yaffs boot file reading code + * + * 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 Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + * + * $Id: yboot.h,v 1.1 2003-01-21 03:32:17 charles Exp $ + */ + + #ifndef __YBOOT_H__ +#define __YBOOT_H__ + +int yaffsboot_InitFile(yaffs_Device *dev, const char *fileName, int *loadedFileSize); + +int yaffsboot_Reinitialise(void); + +int yaffsboot_ReadByte(unsigned char *bPtr); +#endif +