From: Charles Manning Date: Tue, 8 Jun 2010 03:46:58 +0000 (+1200) Subject: yaffs: Add xattrib support X-Git-Tag: pre-name-change~58 X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=commitdiff_plain;h=4a96d43bb566f00596a31a41c535cabbf52d4f20 yaffs: Add xattrib support Signed-off-by: Charles Manning --- diff --git a/Kconfig b/Kconfig index d4363ed..7b3988c 100644 --- a/Kconfig +++ b/Kconfig @@ -178,3 +178,13 @@ config YAFFS_DISABLE_BACKGROUND Background processing makes many foreground activities faster. If unsure, say N. + +config YAFFS_XATTR + bool "Enable yaffs2 xattr support" + depends on YAFFS_FS + default y + help + If this is set then yaffs2 will provide xattr support. + If unsure, say Y. + + diff --git a/Makefile b/Makefile index 919afc0..0119511 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ ifneq ($(KERNELRELEASE),) yaffs2-objs += yaffs_packedtags2.o yaffs_qsort.o yaffs2-objs += yaffs_tagscompat.o yaffs_tagsvalidity.o yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o + yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o yaffs_nameval.o else KERNELDIR ?= /lib/modules/$(shell uname -r)/build diff --git a/direct/Makefile b/direct/Makefile index beec566..4288c69 100644 --- a/direct/Makefile +++ b/direct/Makefile @@ -33,6 +33,7 @@ COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsf yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \ yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \ yaffs_checkptrw.o yaffs_qsort.o\ + yaffs_nameval.o \ yaffs_norif1.o ynorsim.o # yaffs_checkptrwtest.o\ @@ -48,6 +49,7 @@ SYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsin yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \ yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.h \ yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \ + yaffs_nameval.h yaffs_nameval.c \ yaffs_qsort.c yaffs_qsort.h yaffs_trace.h #all: directtest2k boottest diff --git a/direct/dtest.c b/direct/dtest.c index a93e1d0..cf832a9 100644 --- a/direct/dtest.c +++ b/direct/dtest.c @@ -2487,6 +2487,96 @@ void rmdir_test(const char *mountpt) yaffs_rmdir(name); yaffs_unmount(mountpt); } + + + +static void print_xattrib_val(const char *path, const char *name) +{ + char buffer[100]; + int n; + + n = yaffs_getxattr(path,name,buffer,sizeof(buffer)); + if(n >= 0){ + __u8 *b = (__u8 *)buffer; + + printf("%d bytes:",n); + while(n > 0){ + printf("[%02X]",*b); + b++; + n--; + } + printf("\n"); + } else + printf(" Novalue result %d\n",n); +} + +static void list_xattr(const char *path) +{ + char list[1000]; + int n=0; + int list_len; + int len; + + list_len = yaffs_listxattr(path,list,sizeof(list)); + printf("xattribs for %s, result is %d\n",path,list_len); + while(n < list_len){ + len = strlen(list + n); + printf("\"%s\" value ",list+n); + print_xattrib_val(path,list + n); + n += (len + 1); + } + printf("end\n"); +} +void basic_xattr_test(const char *mountpt) +{ + char name[100]; + int h; + int result; + int val1; + int valread; + + yaffs_StartUp(); + + yaffs_mount(mountpt); + + strcpy(name,mountpt); + strcat(name,"/"); + strcat(name,"xfile"); + + yaffs_unlink(name); + h = yaffs_open(name,O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + yaffs_close(h); + + printf("Start\n"); + list_xattr(name); + + printf("Add an attribute\n"); + val1 = 0x123456; + result = yaffs_setxattr(name,"foo",&val1,sizeof(val1),0); + printf("wrote attribute foo: result %d\n",result); + list_xattr(name); + printf("Add an attribute\n"); + val1 = 0x7890; + result = yaffs_setxattr(name,"bar",&val1,sizeof(val1),0); + printf("wrote attribute bar: result %d\n",result); + list_xattr(name); + + printf("Get non-existanrt attribute\n"); + print_xattrib_val(name,"not here"); + + printf("Delete non existing attribute\n"); + yaffs_removexattr(name,"not here"); + list_xattr(name); + + printf("Remove foo\n"); + yaffs_removexattr(name,"foo"); + list_xattr(name); + + printf("Remove bar\n"); + yaffs_removexattr(name,"bar"); + list_xattr(name); + +} int random_seed; @@ -2511,7 +2601,7 @@ int main(int argc, char *argv[]) //fill_empty_files_test("/yaffs2/"); //resize_stress_test("/yaffs2"); - overwrite_test("/yaffs2"); + //overwrite_test("/yaffs2"); //long_name_test("/yaffs2"); //link_test0("/yaffs2"); @@ -2550,6 +2640,8 @@ int main(int argc, char *argv[]) //check_resize_gc_bug("/flash"); + basic_xattr_test("/yaffs2"); + return 0; } diff --git a/direct/python/Makefile b/direct/python/Makefile index 4117d54..4697420 100644 --- a/direct/python/Makefile +++ b/direct/python/Makefile @@ -33,6 +33,7 @@ COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsf yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \ yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \ yaffs_checkptrw.o yaffs_qsort.o\ + yaffs_nameval.o \ yaffs_norif1.o ynorsim.o @@ -44,6 +45,7 @@ YAFFSSYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h ya yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \ yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.h \ yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \ + yaffs_nameval.c yaffs_nameval.h \ yaffs_qsort.c yaffs_qsort.h yaffs_trace.h YAFFSDIRECTSYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffsfs.c yaffs_flashif.h yaffs_flashif2.h\ diff --git a/direct/tests/Makefile b/direct/tests/Makefile index a2d201a..0bd093e 100644 --- a/direct/tests/Makefile +++ b/direct/tests/Makefile @@ -34,6 +34,7 @@ COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsf yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \ yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \ yaffs_checkptrw.o yaffs_qsort.o\ + yaffs_nameval.o \ yaffs_norif1.o ynorsim.o nor_stress.o yaffs_fsx.o # yaffs_checkptrwtest.o\ @@ -49,6 +50,7 @@ YAFFSSYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h ya yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \ yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.h \ yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \ + yaffs_nameval.c yaffs_nameval.h \ yaffs_qsort.c yaffs_qsort.h yaffs_trace.h YAFFSDIRECTSYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffsfs.c yaffs_flashif.h yaffs_flashif2.h\ diff --git a/direct/yaffscfg.h b/direct/yaffscfg.h index 2b46b39..29417c2 100644 --- a/direct/yaffscfg.h +++ b/direct/yaffscfg.h @@ -28,7 +28,7 @@ #define YAFFSFS_N_HANDLES 100 -typedef struct { +typedef struct yaffsfs_DeviceConfigurationStruct { const YCHAR *prefix; struct yaffs_DeviceStruct *dev; } yaffsfs_DeviceConfiguration; diff --git a/direct/yaffscfg2k.c b/direct/yaffscfg2k.c index 781f34b..bfea4f3 100644 --- a/direct/yaffscfg2k.c +++ b/direct/yaffscfg2k.c @@ -181,6 +181,7 @@ int yaffs_StartUp(void) flashDev.param.initialiseNAND = yflash2_InitialiseNAND; flashDev.param.markNANDBlockBad = yflash2_MarkNANDBlockBad; flashDev.param.queryNANDBlock = yflash2_QueryNANDBlock; + flashDev.param.enableXattr = 1; yaffs_initialise(yaffsfs_config); diff --git a/direct/yaffsfs.c b/direct/yaffsfs.c index ddbdcdb..a494e34 100644 --- a/direct/yaffsfs.c +++ b/direct/yaffsfs.c @@ -1180,6 +1180,182 @@ int yaffs_fstat(int fd, struct yaffs_stat *buf) return retVal; } + +/* xattrib functions */ + + +int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_FindObject(NULL,path,0); + + obj = yaffsfs_FollowLink(obj,0); + + if(obj) + retVal = yaffs_SetXAttribute(obj,name,data,size,flags); + else + /* todo error not found */ + yaffsfs_SetError(-ENOENT); + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_GetHandleObject(fd); + + if(obj) + retVal = yaffs_SetXAttribute(obj,name,data,size,flags); + else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_FindObject(NULL,path,0); + + obj = yaffsfs_FollowLink(obj,0); + + if(obj) + retVal = yaffs_GetXAttribute(obj,name,data,size); + else + /* todo error not found */ + yaffsfs_SetError(-ENOENT); + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_fgetxattr(int fd, const char *name, void *data, int size) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_GetHandleObject(fd); + + if(obj) + retVal = yaffs_GetXAttribute(obj,name,data,size); + else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_listxattr(const YCHAR *path, char *data, int size) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_FindObject(NULL,path,0); + + obj = yaffsfs_FollowLink(obj,0); + + if(obj) + retVal = yaffs_ListXAttributes(obj, data,size); + else + /* todo error not found */ + yaffsfs_SetError(-ENOENT); + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_flistxattr(int fd, char *data, int size) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_GetHandleObject(fd); + + if(obj) + retVal = yaffs_ListXAttributes(obj,data,size); + else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_removexattr(const YCHAR *path, const char *name) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_FindObject(NULL,path,0); + + obj = yaffsfs_FollowLink(obj,0); + + if(obj) + retVal = yaffs_RemoveXAttribute(obj,name); + else + /* todo error not found */ + yaffsfs_SetError(-ENOENT); + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_fremovexattr(int fd, const char *name) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_GetHandleObject(fd); + + if(obj) + retVal = yaffs_RemoveXAttribute(obj,name); + else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + #ifdef CONFIG_YAFFS_WINCE int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime) { diff --git a/direct/yaffsfs.h b/direct/yaffsfs.h index fc6152c..18cc22f 100644 --- a/direct/yaffsfs.h +++ b/direct/yaffsfs.h @@ -246,6 +246,19 @@ int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) ; int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) ; int yaffs_fstat(int fd, struct yaffs_stat *buf) ; +int yaffs_setxattr(const char *path, const char *name, const void *data, int size, int flags); +int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags); + +int yaffs_getxattr(const char *path, const char *name, void *data, int size); +int yaffs_fgetxattr(int fd, const char *name, void *data, int size); + +int yaffs_removexattr(const char *path, const char *name); +int yaffs_fremovexattr(int fd, const char *name); + +int yaffs_listxattr(const char *path, char *list, int size); +int yaffs_flistxattr(int fd, char *list, int size); + + #ifdef CONFIG_YAFFS_WINCE int yaffs_set_wince_times(int fd, const unsigned *wctime, const unsigned *watime, const unsigned *wmtime); @@ -285,7 +298,7 @@ loff_t yaffs_totalspace(const YCHAR *path); int yaffs_inodecount(const YCHAR *path); -void yaffs_initialise(yaffsfs_DeviceConfiguration *configList); + int yaffs_StartUp(void); diff --git a/direct/ydirectenv.h b/direct/ydirectenv.h index fc9aefc..d3e2711 100644 --- a/direct/ydirectenv.h +++ b/direct/ydirectenv.h @@ -89,6 +89,8 @@ #define yaffs_SumCompare(x,y) ((x) == (y)) #define yaffs_strcmp(a,b) strcmp(a,b) +#include "yaffsfs.h" + #endif diff --git a/linux-tests/xattrtest.c b/linux-tests/xattrtest.c new file mode 100644 index 0000000..14df34a --- /dev/null +++ b/linux-tests/xattrtest.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include + + +static void print_xattrib_val(const char *path, const char *name) +{ + char buffer[100]; + int n; + + n = getxattr(path,name,buffer,sizeof(buffer)); + if(n >= 0){ + uint8_t *b = (uint8_t *)buffer; + + printf("%d bytes:",n); + while(n > 0){ + printf("[%02X]",*b); + b++; + n--; + } + printf("\n"); + } else + printf(" Novalue result %d\n",n); +} + +static void list_xattr(const char *path) +{ + char list[1000]; + int n=0; + int list_len; + int len; + + list_len = listxattr(path,list,sizeof(list)); + printf("xattribs for %s, result is %d\n",path,list_len); + while(n < list_len){ + len = strlen(list + n); + printf("\"%s\" value ",list+n); + print_xattrib_val(path,list + n); + n += (len + 1); + } + printf("end\n"); + +} + +void basic_xattr_test(const char *mountpt) +{ + char name[100]; + int h; + int result; + int val1; + int valread; + + + strcpy(name,mountpt); + strcat(name,"/"); + strcat(name,"xfile"); + + unlink(name); + h = open(name,O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + close(h); + + printf("Start\n"); + list_xattr(name); + + printf("Add an attribute\n"); + val1 = 0x123456; + result = setxattr(name,"foo",&val1,sizeof(val1),0); + printf("wrote attribute foo: result %d\n",result); + list_xattr(name); + printf("Add an attribute\n"); + val1 = 0x7890; + result = setxattr(name,"bar",&val1,sizeof(val1),0); + printf("wrote attribute bar: result %d\n",result); + list_xattr(name); + + printf("Get non-existanrt attribute\n"); + print_xattrib_val(name,"not here"); + + printf("Delete non existing attribute\n"); + removexattr(name,"not here"); + list_xattr(name); + + printf("Remove foo\n"); + removexattr(name,"foo"); + list_xattr(name); + + printf("Remove bar\n"); + removexattr(name,"bar"); + list_xattr(name); + +} + + +int random_seed; +int simulate_power_failure; + +int main(int argc, char *argv[]) +{ + basic_xattr_test("/mnt/"); +} diff --git a/moduleconfig.h b/moduleconfig.h index e8efd67..43f1144 100644 --- a/moduleconfig.h +++ b/moduleconfig.h @@ -63,6 +63,10 @@ /* #define CONFIG_DISABLE_BACKGROUND */ +/* Default: Selected */ +/* Meaning: Enable XATTR support */ +#define CONFIG_YAFFS_XATTR + /* Older-style on-NAND data format has a "pageStatus" byte to record chunk/page state. This byte is zeroed when the page is discarded. diff --git a/yaffs_fs.c b/yaffs_fs.c index 6eb356c..b4ee69e 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -264,6 +264,15 @@ static int yaffs_writepage(struct page *page, struct writeback_control *wbc); static int yaffs_writepage(struct page *page); #endif +#ifdef CONFIG_YAFFS_XATTR +int yaffs_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags); +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff, + size_t size); +int yaffs_removexattr(struct dentry *dentry, const char *name); +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size); +#endif + #if (YAFFS_USE_WRITE_BEGIN_END != 0) static int yaffs_write_begin(struct file *filp, struct address_space *mapping, @@ -355,12 +364,24 @@ static void zero_user_segment(struct page *page, unsigned start, unsigned end) static const struct inode_operations yaffs_file_inode_operations = { .setattr = yaffs_setattr, +#ifdef CONFIG_YAFFS_XATTR + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +#endif }; static const struct inode_operations yaffs_symlink_inode_operations = { .readlink = yaffs_readlink, .follow_link = yaffs_follow_link, .setattr = yaffs_setattr, +#ifdef CONFIG_YAFFS_XATTR + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +#endif }; static const struct inode_operations yaffs_dir_inode_operations = { @@ -374,6 +395,12 @@ static const struct inode_operations yaffs_dir_inode_operations = { .mknod = yaffs_mknod, .rename = yaffs_rename, .setattr = yaffs_setattr, +#ifdef CONFIG_YAFFS_XATTR + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +#endif }; static const struct file_operations yaffs_dir_operations = { @@ -1836,6 +1863,124 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) return error; } +#ifdef CONFIG_YAFFS_XATTR +int yaffs_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + yaffs_Device *dev; + yaffs_Object *obj = yaffs_InodeToObject(inode); + + T(YAFFS_TRACE_OS, + (TSTR("yaffs_setxattr of object %d\n"), + obj->objectId)); + + + if (error == 0) { + int result; + dev = obj->myDev; + yaffs_GrossLock(dev); + result = yaffs_SetXAttribute(obj, name, value, size, flags); + if(result == YAFFS_OK) + error = 0; + else if(result < 0) + error = result; + yaffs_GrossUnlock(dev); + + } + T(YAFFS_TRACE_OS, + (TSTR("yaffs_setxattr done returning %d\n"),error)); + + return error; +} + + +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff, + size_t size) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + yaffs_Device *dev; + yaffs_Object *obj = yaffs_InodeToObject(inode); + + T(YAFFS_TRACE_OS, + (TSTR("yaffs_getxattr of object %d\n"), + obj->objectId)); + + + if (error == 0) { + dev = obj->myDev; + yaffs_GrossLock(dev); + error = yaffs_GetXAttribute(obj, name, buff, size); + yaffs_GrossUnlock(dev); + + } + T(YAFFS_TRACE_OS, + (TSTR("yaffs_getxattr done returning %d\n"),error)); + + return error; +} + +int yaffs_removexattr(struct dentry *dentry, const char *name) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + yaffs_Device *dev; + yaffs_Object *obj = yaffs_InodeToObject(inode); + + T(YAFFS_TRACE_OS, + (TSTR("yaffs_removexattr of object %d\n"), + obj->objectId)); + + + if (error == 0) { + int result; + dev = obj->myDev; + yaffs_GrossLock(dev); + result = yaffs_RemoveXAttribute(obj, name); + if(result == YAFFS_OK) + error = 0; + else if(result < 0) + error = result; + yaffs_GrossUnlock(dev); + + } + T(YAFFS_TRACE_OS, + (TSTR("yaffs_removexattr done returning %d\n"),error)); + + return error; +} + +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + yaffs_Device *dev; + yaffs_Object *obj = yaffs_InodeToObject(inode); + + T(YAFFS_TRACE_OS, + (TSTR("yaffs_listxattr of object %d\n"), + obj->objectId)); + + + if (error == 0) { + int result; + dev = obj->myDev; + yaffs_GrossLock(dev); + error = yaffs_ListXAttributes(obj, buff, size); + yaffs_GrossUnlock(dev); + + } + T(YAFFS_TRACE_OS, + (TSTR("yaffs_listxattr done returning %d\n"),error)); + + return error; +} + +#endif + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) { @@ -2625,6 +2770,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD param->disableLazyLoad = 1; +#endif +#ifdef CONFIG_YAFFS_XATTR + param->enableXattr = 1; #endif if(options.lazy_loading_overridden) param->disableLazyLoad = !options.lazy_loading_enabled; diff --git a/yaffs_guts.c b/yaffs_guts.c index 9509dd4..385b267 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -29,6 +29,8 @@ #include "yaffs_nand.h" #include "yaffs_packedtags2.h" +#include "yaffs_nameval.h" + /* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ #define YAFFS_GC_GOOD_ENOUGH 2 @@ -46,6 +48,15 @@ #include "yaffs_ecc.h" +/* Private structure for doing xattr modifications */ +typedef struct { + int set; /* If 0 then this is a deletion */ + const char *name; + const void *data; + int size; + int flags; + int result; +} yaffs_XAttrMod; /* Robustification (if it ever comes about...) */ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND); @@ -76,7 +87,9 @@ static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj); static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, - int force, int isShrink, int shadows); + int force, int isShrink, int shadows, yaffs_XAttrMod *xop); +static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod); + static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); static int yaffs_DoGenericObjectDeletion(yaffs_Object *in); @@ -2519,7 +2532,7 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, break; } - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { + if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0, NULL) < 0) { /* Could not create the object header, fail the creation */ yaffs_DeleteObject(in); in = NULL; @@ -2627,7 +2640,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, obj->unlinked = 1; /* If it is a deletion then we mark it as a shrink for gc purposes. */ - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0) + if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows, NULL) >= 0) return YAFFS_OK; } @@ -4048,7 +4061,7 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, * If name is not NULL, then that new name is used. */ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, - int isShrink, int shadows) + int isShrink, int shadows, yaffs_XAttrMod *xmod) { yaffs_BlockInfo *bi; @@ -4074,7 +4087,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, if (!in->fake || in == dev->rootDir || /* The rootDir should also be saved */ - force) { + force || xmod) { yaffs_CheckGarbageCollection(dev,0); yaffs_CheckObjectDetailsLoaded(in); @@ -4091,9 +4104,9 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, yaffs_VerifyObjectHeader(in, oh, &oldTags, 0); memcpy(oldName, oh->name, sizeof(oh->name)); - } - - memset(buffer, 0xFF, dev->nDataBytesPerChunk); + memset(buffer, 0xFF, sizeof(yaffs_ObjectHeader)); + } else + memset(buffer, 0xFF, dev->nDataBytesPerChunk); oh->type = in->variantType; oh->yst_mode = in->yst_mode; @@ -4161,6 +4174,11 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, break; } + /* process any xattrib modifications */ + if(xmod) + yaffs_ApplyXMod(dev, (char *)buffer, xmod); + + /* Tags */ yaffs_InitialiseTags(&newTags); in->serial++; @@ -5469,7 +5487,7 @@ static int yaffs_HandleHole(yaffs_Object *obj, loff_t newSize) obj->parent->objectId != YAFFS_OBJECTID_UNLINKED && obj->parent->objectId != YAFFS_OBJECTID_DELETED){ /* Write a hole start header with the old file size */ - yaffs_UpdateObjectHeader(obj, NULL, 0,1,0); + yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL); } return result; @@ -5509,7 +5527,7 @@ int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) !in->isShadowed && in->parent->objectId != YAFFS_OBJECTID_UNLINKED && in->parent->objectId != YAFFS_OBJECTID_DELETED) - yaffs_UpdateObjectHeader(in, NULL, 0,0,0); + yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL); return YAFFS_OK; @@ -5553,7 +5571,7 @@ int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync) #endif } - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >= + retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >= 0) ? YAFFS_OK : YAFFS_FAIL; } } else { @@ -6478,7 +6496,7 @@ static int yaffs_Scan(yaffs_Device *dev) obj = yaffs_FindObjectByNumber(dev, fixer->objectId); if (obj) - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL); YFREE(fixer); } @@ -7312,7 +7330,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj) } } else - yaffs_UpdateObjectHeader(obj,NULL,0,0,0); + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL); } void yaffs_UpdateDirtyDirectories(yaffs_Device *dev) @@ -7335,7 +7353,7 @@ void yaffs_UpdateDirtyDirectories(yaffs_Device *dev) T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->objectId)); if(obj->dirty) - yaffs_UpdateObjectHeader(obj,NULL,0,0,0); + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL); } } @@ -7666,7 +7684,7 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr) if (valid & ATTR_SIZE) yaffs_ResizeFile(obj, attr->ia_size); - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL); return YAFFS_OK; @@ -7699,6 +7717,104 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) #endif + +static int yaffs_DoXMod(yaffs_Object *obj, int set, const char *name, const void *value, int size, int flags) +{ + yaffs_XAttrMod xmod; + + int result; + + xmod.set = set; + xmod.name = name; + xmod.data = value; + xmod.size = size; + xmod.flags = flags; + xmod.result = -ENOSPC; + + result = yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, &xmod); + + if(result > 0) + return xmod.result; + else + return -ENOSPC; +} + +static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod) +{ + int retval = 0; + int x_offs = sizeof(yaffs_ObjectHeader); + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader); + + char * x_buffer = buffer + x_offs; + + if(xmod->set) + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags); + else + retval = nval_del(x_buffer, x_size, xmod->name); + + xmod->result = retval; + + return retval; +} + +static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int size) +{ + char *buffer = NULL; + int result; + yaffs_ExtendedTags tags; + yaffs_Device *dev = obj->myDev; + int x_offs = sizeof(yaffs_ObjectHeader); + int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader); + + __u8 * x_buffer; + + int retval = 0; + + if(obj->hdrChunk < 1) + return -ENOENT; + + buffer = yaffs_GetTempBuffer(dev, __LINE__); + if(!buffer) + return -ENOMEM; + + result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, buffer, &tags); + + if(result != YAFFS_OK) + retval = -ENOENT; + else{ + x_buffer = buffer + x_offs; + + if(name) + retval = nval_get(x_buffer, x_size, name, value, size); + else + retval = nval_list(x_buffer, x_size, value,size); + } + yaffs_ReleaseTempBuffer(dev,buffer,__LINE__); + return retval; +} + +int yaffs_SetXAttribute(yaffs_Object *obj, const char *name, const void * value, int size, int flags) +{ + return yaffs_DoXMod(obj, 1, name, value, size, flags); +} + +int yaffs_RemoveXAttribute(yaffs_Object *obj, const char *name) +{ + return yaffs_DoXMod(obj, 0, name, NULL, 0, 0); +} + +int yaffs_GetXAttribute(yaffs_Object *obj, const char *name, void *value, int size) +{ + return yaffs_DoXFetch(obj, name, value, size); +} + +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size) +{ + return yaffs_DoXFetch(obj, NULL, buffer,size); +} + + + #if 0 int yaffs_DumpObject(yaffs_Object *obj) { diff --git a/yaffs_guts.h b/yaffs_guts.h index 3647d6b..84b53aa 100644 --- a/yaffs_guts.h +++ b/yaffs_guts.h @@ -564,6 +564,8 @@ struct yaffs_DeviceParamStruct { __u8 skipCheckpointRead; __u8 skipCheckpointWrite; + int enableXattr; /* Enable xattribs */ + /* NAND access functions (Must be set before calling YAFFS)*/ int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev, @@ -886,6 +888,12 @@ YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj); yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev); + +int yaffs_SetXAttribute(yaffs_Object *obj, const char *name, const void * value, int size, int flags); +int yaffs_GetXAttribute(yaffs_Object *obj, const char *name, void *value, int size); +int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size); +int yaffs_RemoveXAttribute(yaffs_Object *obj, const char *name); + /* Special directories */ yaffs_Object *yaffs_Root(yaffs_Device *dev); yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); diff --git a/yaffs_nameval.c b/yaffs_nameval.c new file mode 100644 index 0000000..88ee25b --- /dev/null +++ b/yaffs_nameval.c @@ -0,0 +1,196 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2010 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * 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 simple implementation of a name-value store assumes a small number of values and fits + * into a small finite buffer. + * + * Each attribute is stored as a record: + * sizeof(int) bytes record size. + * strnlen+1 bytes name null terminated. + * nbytes value. + * ---------- + * total size stored in record size + */ + + +#include "yaffs_nameval.h" + +#include "yportenv.h" + +static int nval_find(const char *xb, int xb_size, const char *name) +{ + int pos=0; + int size; + + memcpy(&size,xb,sizeof(int)); + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ + if(strncmp(xb+pos+sizeof(int),name,size) == 0) + return pos; + pos += size; + if(pos < xb_size -sizeof(int)) + memcpy(&size,xb + pos,sizeof(int)); + else + size = 0; + } + return -1; +} + +static int nval_used(const char *xb, int xb_size) +{ + int pos=0; + int size; + + memcpy(&size,xb + pos,sizeof(int)); + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ + pos += size; + if(pos < xb_size -sizeof(int)) + memcpy(&size,xb + pos,sizeof(int)); + else + size = 0; + } + return pos; +} + +int nval_del(char *xb, int xb_size, const char *name) +{ + int pos = nval_find(xb, xb_size, name); + int size; + + if(pos >= 0 && pos < xb_size){ + /* Find size, shift rest over this record, then zero out the rest of buffer */ + memcpy(&size,xb+pos,sizeof(int)); + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); + memset(xb + (xb_size - size),0,size); + return 0; + } else + return -ENOENT; +} + +int nval_set(char *xb, int xb_size, const char *name, const char *buf, int bsize, int flags) +{ + int pos = nval_find(xb,xb_size,name); + int namelen = strnlen(name,xb_size); + int reclen; + + if(flags & NVAL_CREATE && pos >= 0) + return -EEXIST; + if(flags & NVAL_REPLACE && pos < 0) + return -ENOENT; + + nval_del(xb,xb_size,name); + + pos = nval_used(xb, xb_size); + + if(pos < xb_size && bsize < xb_size && namelen < xb_size){ + reclen = (sizeof(int) + namelen + 1 + bsize); + if( pos + reclen < xb_size){ + memcpy(xb + pos,&reclen,sizeof(int)); + pos +=sizeof(int); + strncpy(xb + pos, name, reclen); + pos+= (namelen+1); + memcpy(xb + pos,buf,bsize); + pos+= bsize; + return 0; + } + } + return -ENOSPC; +} + +int nval_get(const char *xb, int xb_size, const char *name, char *buf, int bsize) +{ + int pos = nval_find(xb,xb_size,name); + int size; + + if(pos >= 0 && pos< xb_size){ + + memcpy(&size,xb +pos,sizeof(int)); + pos+=sizeof(int); /* advance past record length */ + size -= sizeof(int); + + /* Advance over name string */ + while(xb[pos] && size > 0 && pos < xb_size){ + pos++; + size--; + } + /*Advance over NUL */ + pos++; + size--; + + if(size <= bsize){ + memcpy(buf,xb + pos,size); + return size; + } + + } + return -ENOENT; +} + +int nval_list(const char *xb, int xb_size, char *buf, int bsize) +{ + int pos = 0; + int size; + int name_len; + int ncopied = 0; + int filled = 0; + + memcpy(&size,xb + pos,sizeof(int)); + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){ + pos+= sizeof(int); + size-=sizeof(int); + name_len = strnlen(xb + pos, size); + if(ncopied + name_len + 1 < bsize){ + memcpy(buf,xb+pos,name_len); + buf+= name_len; + *buf = '\0'; + buf++; + ncopied += (name_len+1); + } else + filled = 1; + pos+=size; + if(pos < xb_size -sizeof(int)) + memcpy(&size,xb + pos,sizeof(int)); + else + size = 0; + } + return ncopied; +} + +int nval_load(char *xb, int xb_size, const char *src, int src_size) +{ + int tx_size; + int used; + + tx_size = xb_size; + if(tx_size > src_size) + tx_size = src_size; + + memcpy(xb,src,tx_size); + used = nval_used(xb, xb_size); + + if( used < xb_size) + memset(xb+ used, 0, xb_size - used); + return used; +} + +int nval_save(const char *xb, int xb_size, char *dest, int dest_size) +{ + int tx_size; + + tx_size = xb_size; + if(tx_size > dest_size) + tx_size = dest_size; + + memcpy(dest,xb,tx_size); + return tx_size; +} diff --git a/yaffs_nameval.h b/yaffs_nameval.h new file mode 100644 index 0000000..ad81005 --- /dev/null +++ b/yaffs_nameval.h @@ -0,0 +1,14 @@ +#ifndef __NAMEVAL_H__ +#define __NAMEVAL_H__ + +#define NVAL_CREATE 0x01 +#define NVAL_REPLACE 0x02 + +int nval_del(char *xb, int xb_size, const char *name); +int nval_set(char *xb, int xb_size, const char *name, const char *buf, int bsize, int flags); +int nval_get(const char *xb, int xb_size, const char *name, char *buf, int bsize); +int nval_list(const char *xb, int xb_size, char *buf, int bsize); +int nval_load(char *xb, int xb_size, const char *src, int src_size); +int nval_save(const char *xb, int xb_size, char *dest, int dest_size); + +#endif