yaffs: Add xattrib support
authorCharles Manning <cdhmanning@gmail.com>
Tue, 8 Jun 2010 03:46:58 +0000 (15:46 +1200)
committerCharles Manning <cdhmanning@gmail.com>
Tue, 8 Jun 2010 03:46:58 +0000 (15:46 +1200)
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
18 files changed:
Kconfig
Makefile
direct/Makefile
direct/dtest.c
direct/python/Makefile
direct/tests/Makefile
direct/yaffscfg.h
direct/yaffscfg2k.c
direct/yaffsfs.c
direct/yaffsfs.h
direct/ydirectenv.h
linux-tests/xattrtest.c [new file with mode: 0644]
moduleconfig.h
yaffs_fs.c
yaffs_guts.c
yaffs_guts.h
yaffs_nameval.c [new file with mode: 0644]
yaffs_nameval.h [new file with mode: 0644]

diff --git a/Kconfig b/Kconfig
index d4363edcdbfe685f2c3a3bc6b1c0add79b26379e..7b3988c3a01474d89b742d253c1d82793876b96a 100644 (file)
--- 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.
+
+
index 919afc054668812eae28188918c5ac429905eb51..01195115b38acad73a5d4897402ddc6bb767b73b 100644 (file)
--- 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
index beec566b925fcef9d5436f9f2abad0daa2c41b86..4288c692cd9331a3a4fbb90eab4f5ee9a44206f4 100644 (file)
@@ -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
index a93e1d05071a135a036591468720730368b7442e..cf832a957ea71f901044b9fa5c3fc006839865ff 100644 (file)
@@ -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;
        
 }
index 4117d5485be5fe702d0e054aa5b645eff8d9656b..4697420a54100e0e43c822e6fb22a872576be62f 100644 (file)
@@ -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\
index a2d201a7414cfa01f8ed85e82a438a0193857a61..0bd093eb2e176894d15a86ce6fe44628ff3b3b85 100644 (file)
@@ -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\
index 2b46b392d3a55fb61ac142a5aad05ce2561fd9e8..29417c2028672112f9ba07fcad849f442e49860d 100644 (file)
@@ -28,7 +28,7 @@
 #define YAFFSFS_N_HANDLES 100
 
 
-typedef struct {
+typedef struct yaffsfs_DeviceConfigurationStruct {
        const YCHAR *prefix;
        struct yaffs_DeviceStruct *dev;
 } yaffsfs_DeviceConfiguration;
index 781f34b6849ea8a16d1af7f58e1c0b2ae8336e58..bfea4f303fee3f82f33f1ee8853d328a3eb2b62e 100644 (file)
@@ -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);
index ddbdcdb65354743c00bc02efc70e8111044f6119..a494e34ca67612b093ea97899d4d05215324b477 100644 (file)
@@ -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)
 {
index fc6152ceaf37e2c4751992720ff2a64c3a452868..18cc22ff2e525ef0e6bd8498cbd72a90f8c0db58 100644 (file)
@@ -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);
 
index fc9aefc1fb3beb02cbb6deb34d7fb865d7ed3b84..d3e27114eedf081a2360e81326a71e33a68f547e 100644 (file)
@@ -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 (file)
index 0000000..14df34a
--- /dev/null
@@ -0,0 +1,103 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+
+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/");      
+}
index e8efd67586a7c3fe7764695e06eb0dfadf1ce101..43f11447601dbdd8a6e852b02acd35220cf53879 100644 (file)
 /* #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.
index 6eb356c81e6e4276c0ca88813e7b83082b788bd9..b4ee69edf1f9642cc9ffc8bbc12bc931d3bb4b24 100644 (file)
@@ -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;
index 9509dd401a33e5e9eb0a6989f74f733b1cc33d61..385b26778fbff66aa1e872800f4452ae5773ed17 100644 (file)
@@ -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
 
 #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)
 {
index 3647d6bce6cd629dfcc483edead75c5519809a17..84b53aacf05403fd2c9a927cbdf0b13b10fa8e13 100644 (file)
@@ -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 (file)
index 0000000..88ee25b
--- /dev/null
@@ -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 <charles@aleph1.co.uk>
+ *
+ * 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 (file)
index 0000000..ad81005
--- /dev/null
@@ -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