diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
index c0e545b..a939904 100644
--- a/fs/yaffs2/Kconfig
+++ b/fs/yaffs2/Kconfig
@@ -31,6 +31,30 @@ config YAFFS_YAFFS1
Ifunsure, say Y.
+config YAFFS_XATTR
+ bool"YAFFS extended attributes"
+ depends onYAFFS_FS
+ default n
+ help
+ Extended attributes are name:value pairsassociated with inodes by
+ the kernel or by users (see the attr(5)manual page, or visit
+ <http://acl.bestbits.at/> for details).
+
+ If unsure, say N.
+
+config YAFFS_SECURITY
+ bool"YAFFS Security Labels"
+ depends onYAFFS_XATTR
+ default n
+ help
+ Security labels support alternative accesscontrol models
+ implemented by security modules likeSELinux. This option
+ enables an extended attribute handler forfile security
+ labels in the yaffs filesystem.
+
+ If you are not using a security module thatrequires using
+ extended attributes for file security labels,say N.
+
configYAFFS_9BYTE_TAGS
bool "Use older-style on-NAND dataformat with pageStatus byte"
depends on YAFFS_YAFFS1
diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile
index 382ee61..fa7810d 100644
--- a/fs/yaffs2/Makefile
+++ b/fs/yaffs2/Makefile
@@ -8,3 +8,6 @@ yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.oyaffs_checkptrw.o
yaffs-y +=yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
yaffs-y +=yaffs_tagscompat.o yaffs_tagsvalidity.o
yaffs-y +=yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
+
+yaffs-$(CONFIG_YAFFS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
+yaffs-$(CONFIG_YAFFS_SECURITY) += xattr_security.o
diff --git a/fs/yaffs2/xattr.c b/fs/yaffs2/xattr.c
new file mode 100644
index 0000000..36efc0e
--- /dev/null
+++ b/fs/yaffs2/xattr.c
@@ -0,0 +1,450 @@
+/*
+ * Extended Attribute support for YAFFS
+ *
+ * Copyright (c) 2010 The Pennsylvania StateUniversity
+ * Systems and Internet Infrastructure SecurityLaboratory
+ *
+ * Created by William Enck <[email protected]>
+ * Acknowledgements:
+ * - General xattr handler structure taken from EXT2FS XATTR implementation
+ *
+ * This program is free software; you canredistribute it and/or modify
+ * it under the terms of the GNU General PublicLicense version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Extended attributes are stored as files in ahidden XATTR directory.
+ * If a file has an XATTR, a new directory with thestring representation
+ * of the object ID is created in the XATTRdirectory. A file in that
+ * directory is created for each named XATTR.
+ *
+ * yaffs_guts.c is modified to clean up these filesand directories on
+ * object unlink.
+ *
+ * Locking strategy
+ * ----------------
+ * Theyaffs_fs.c module uses a gross lock on the device when accessing
+ * files. TheXATTR code uses this same lock for set, get, and list.
+ */
+
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6,19))
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+
+#include "yaffs_guts.h"
+#include "xattr.h"
+
+/* Macros defined in yaffs_fs.c that are needed here*/
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6,18))
+#define yaffs_InodeToObjectLV(iptr)((iptr)->i_private)
+#else
+#define yaffs_InodeToObjectLV(iptr)((iptr)->u.generic_ip)
+#endif
+#define yaffs_InodeToObject(iptr) ((yaffs_Object*)(yaffs_InodeToObjectLV(iptr)))
+#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
+
+/* function defined in yaffs_fs.c that is needed here*/
+static void yaffs_GrossLock(yaffs_Device *dev)
+{
+ T(YAFFS_TRACE_OS,("yaffs locking %p\n", current));
+ down(&dev->grossLock);
+ T(YAFFS_TRACE_OS,("yaffs locked %p\n", current));
+}
+
+/* function defined in yaffs_fs.c that is needed here*/
+static void yaffs_GrossUnlock(yaffs_Device *dev)
+{
+ T(YAFFS_TRACE_OS,("yaffs unlocking %p\n", current));
+ up(&dev->grossLock);
+}
+
+struct xattr_handler *yaffs_xattr_handlers[] = {
+ &yaffs_xattr_user_handler,
+ &yaffs_xattr_trusted_handler,
+#ifdef CONFIG_YAFFS_SECURITY
+ &yaffs_xattr_security_handler,
+#endif
+ NULL
+};
+
+static const char *
+yaffs_xattr_prefix(int name_index)
+{
+ switch (name_index){
+ caseYAFFS_XATTR_INDEX_USER:
+ returnXATTR_USER_PREFIX;
+ caseYAFFS_XATTR_INDEX_TRUSTED:
+ returnXATTR_TRUSTED_PREFIX;
+ caseYAFFS_XATTR_INDEX_SECURITY:
+ returnXATTR_SECURITY_PREFIX;
+ }
+
+ return NULL;
+}
+
+static struct xattr_handler*
+yaffs_xattr_handler(const YCHAR *name)
+{
+ if(strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) == 0)
+ return&yaffs_xattr_user_handler;
+ if(strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0)
+ return&yaffs_xattr_trusted_handler;
+#ifdef CONFIG_YAFFS_SECURITY
+ if(strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0)
+ return&yaffs_xattr_security_handler;
+#endif
+ return NULL;
+}
+
+static int
+yaffs_xattr_name(int name_index, const char *name,
+ char*xname, size_t xname_size)
+{
+ inttotal_len;
+ const char*prefix = yaffs_xattr_prefix(name_index);
+
+ total_len =strlen(prefix) + strlen(name) + 1;
+
+ if(xname_size < total_len) {
+ return-1;
+ }
+
+ snprintf(xname,xname_size, "%s%s", prefix, name);
+
+ return 0;
+}
+
+/*
+ * yaffs_xattr_get()
+ *
+ * Copy an extended attribute into the bufferprovided, or compute the
+ * buffer size required. Buffer is NULL to copmutethe size of the
+ * buffer required.
+ *
+ * Returns a negative error number on failure, or thenumber of bytes
+ * used / required on success.
+ */
+int
+yaffs_xattr_get(struct inode *inode, int name_index,const char *name,
+ void*buffer, size_t buffer_size)
+{
+ int error;
+ yaffs_Device*dev;
+ yaffs_Object*iobj = NULL; /* inode object */
+ yaffs_Object*aobj = NULL; /* xattr directory object */
+ yaffs_Object*xobj = NULL; /* xattr data object */
+ charobjectStr[YAFFS_OBJECTID_STRLEN+1];
+ YCHARxname[YAFFS_MAX_NAME_LENGTH+1];
+ int size;
+
+ iobj =yaffs_InodeToObject(inode);
+ dev =iobj->myDev; /* Assumes inode was valid */
+
+ if (name ==NULL)
+ return-EINVAL;
+
+ /* Determinethe directory name used in the xattr directory */
+ iobj = yaffs_GetEquivalentObject(iobj);/* TODO: necessary? */
+ snprintf(objectStr,YAFFS_OBJECTID_STRLEN+1, "%d", iobj->objectId);
+
+ /* Create thexattr name string */
+ if(yaffs_xattr_name(name_index, name,
+ xname, YAFFS_MAX_NAME_LENGTH+1) < 0) {
+ return-EINVAL;
+ }
+
+ yaffs_GrossLock(dev);
+
+ error =-ENODATA;
+ aobj =yaffs_FindObjectByName(dev->xattrsDir, objectStr);
+ if (aobj) {
+ xobj =yaffs_FindObjectByName(aobj, xname);
+ }
+
+ if (xobj) {
+ size =xobj->variant.fileVariant.fileSize;
+
+ if(buffer == NULL) {
+ /*return the value size */
+ error= size;
+ gotocleanup;
+ }
+
+ if(buffer_size < size) {
+ error= -ERANGE;
+ gotocleanup;
+ }
+
+ /* Readthe whole thing */
+ error =yaffs_ReadDataFromFile(xobj, buffer, 0, size);
+ }
+
+cleanup:
+ yaffs_GrossUnlock(dev);
+
+ return error;
+}
+
+#if 0
+/* Debugging utility */
+static void yaffs_dump_xattr_dir(yaffs_Device *dev)
+{
+ yaffs_Object*aobj = NULL; /* xattr directory object */
+ yaffs_Object*xobj = NULL; /* xattr data object */
+ charobjectStr[YAFFS_OBJECTID_STRLEN+1];
+ YCHARxname[YAFFS_MAX_NAME_LENGTH + 1];
+ structylist_head *i, *j; /* list cursors */
+
+ T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_dump_xattr_dir:"TENDSTR)));
+
+ ylist_for_each(i,&dev->xattrsDir->variant.directoryVariant.children) {
+ if (!i)
+ continue;
+ aobj =ylist_entry(i, yaffs_Object, siblings);
+
+ yaffs_GetObjectName(aobj,objectStr, YAFFS_OBJECTID_STRLEN + 1);
+
+ T(YAFFS_TRACE_ALWAYS,(TSTR("-%s"TENDSTR),objectStr));
+
+ ylist_for_each(j,&aobj->variant.directoryVariant.children) {
+ if(!j)
+ continue;
+ xobj= ylist_entry(j, yaffs_Object, siblings);
+
+ yaffs_GetObjectName(xobj,xname, YAFFS_MAX_NAME_LENGTH + 1);
+
+ T(YAFFS_TRACE_ALWAYS,(TSTR("--%s"TENDSTR),xname));
+ }
+
+ }
+}
+#endif
+
+/*
+ * yaffs_xattr_list()
+ *
+ * Copy a list of attribute names into the bufferprovided, or compute the
+ * buffers size required. Buffer is NULL to computethe size of the buffer
+ * required.
+ *
+ * Returns a negative error number on failure, or thenumber of bytes
+ * used / required on success
+ */
+static int
+yaffs_xattr_list(struct inode *inode, char *buffer,size_t buffer_size)
+{
+ int error;
+ yaffs_Device*dev;
+ yaffs_Object*iobj = NULL; /* inode object */
+ yaffs_Object*aobj = NULL; /* xattr directory object */
+ yaffs_Object*cobj = NULL; /* cursor object */
+ structylist_head *cur; /* list cursor */
+ int rest;
+ char objectStr[YAFFS_OBJECTID_STRLEN+1];
+ YCHARxname[YAFFS_MAX_NAME_LENGTH + 1];
+
+ iobj =yaffs_InodeToObject(inode);
+ dev =iobj->myDev;
+
+ //yaffs_dump_xattr_dir(dev);
+
+ /* Determinethe directory name used in the xattr directory */
+ iobj = yaffs_GetEquivalentObject(iobj);/* TODO: necessary? */
+ snprintf(objectStr,YAFFS_OBJECTID_STRLEN+1, "%d", iobj->objectId);
+
+ yaffs_GrossLock(dev);
+
+ aobj =yaffs_FindObjectByName(dev->xattrsDir, objectStr);
+ if (!aobj) {
+ /* Noxattrs */
+ error =0;
+ gotocleanup;
+ }
+
+ if(aobj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("yaffs_xattr_list:xattr directory not a directory! (objectId = %d)"TENDSTR),
+ aobj->objectId));
+ error =0;
+ goto cleanup;
+ }
+
+ rest =buffer_size;
+ ylist_for_each(cur,&aobj->variant.directoryVariant.children) {
+ structxattr_handler *handler;
+
+ if (!cur)
+ continue;
+ cobj =ylist_entry(cur, yaffs_Object, siblings);
+
+ yaffs_GetObjectName(cobj,xname, YAFFS_MAX_NAME_LENGTH + 1);
+
+ handler =yaffs_xattr_handler(xname);
+ if(handler) {
+ size_tsize = handler->list(inode, buffer, rest,
+ xname, strlen(xname));
+ if(buffer) {
+ if(size > rest) {
+ error= -ERANGE;
+ gotocleanup;
+ }
+ buffer+= size;
+ }
+ rest-= size;
+ }
+ }
+
+ error =buffer_size - rest; /* total size */
+
+cleanup:
+ yaffs_GrossUnlock(dev);
+
+ return error;
+}
+
+/*
+ * Inode operation listxattr()
+ *
+ * dentry->d_inode->i_mutex: don't care
+ */
+ssize_t
+yaffs_listxattr(struct dentry *dentry, char *buffer,size_t size)
+{
+ returnyaffs_xattr_list(dentry->d_inode, buffer, size);
+}
+
+static int
+yaffs_xattr_set2(yaffs_Object *xobj, const void*value, size_t value_len)
+{
+ int error =-EIO;
+
+ /* Truncatethe existing contents */
+ if(yaffs_ResizeFile(xobj, 0) == YAFFS_FAIL) {
+ error =-EIO;
+ goto out;
+ }
+
+ if (value_len== 0) {
+ /* We aredone */
+ error =0;
+ goto out;
+ }
+
+ error =yaffs_WriteDataToFile(xobj, value, 0, value_len, 1);
+
+out:
+ return error;
+}
+
+/*
+ * yaffs_xattr_set()
+ *
+ * Create, replace, or remove an extended attributefor this inode. Buffer
+ * is NULL to remove an existing extended attribute,and non-NULL to
+ * either replace an existing extended attribute, orcreate a new extended
+ * attribute. The flags XATTR_REPLACE andXATTR_CREATE
+ * specify that an extended attribute must exist andmust not exist
+ * previous to the call, respectively.
+ *
+ * Returns 0, or a negative number on failure.
+ */
+int
+yaffs_xattr_set(struct inode *inode, int name_index,const char *name,
+ constvoid *value, size_t value_len, int flags)
+{
+ int error;
+ yaffs_Device*dev;
+ yaffs_Object*iobj = NULL; /* inode object */
+ yaffs_Object*aobj = NULL; /* xattr directory object */
+ yaffs_Object*xobj = NULL; /* xattr value object */
+ charobjectStr[YAFFS_OBJECTID_STRLEN+1];
+ YCHARxname[YAFFS_MAX_NAME_LENGTH + 1];
+
+ iobj =yaffs_InodeToObject(inode);
+ dev =iobj->myDev; /* Assumes inode was valid */
+
+ if (name ==NULL)
+ return-EINVAL;
+ if(strlen(name) > YAFFS_MAX_NAME_LENGTH)
+ return-ERANGE;
+
+ /* Determinethe directory name used in the xattr directory */
+ iobj =yaffs_GetEquivalentObject(iobj); /* TODO: necessary? */
+ snprintf(objectStr,YAFFS_OBJECTID_STRLEN+1, "%d", iobj->objectId);
+
+ /* Create thexattr name string */
+ if(yaffs_xattr_name(name_index, name,
+ xname, YAFFS_MAX_NAME_LENGTH+1) < 0) {
+ return-EINVAL;
+ }
+
+ yaffs_GrossLock(dev);
+
+ /* See ifthis object already has an xattr directory associated with it */
+ aobj =yaffs_FindObjectByName(dev->xattrsDir, objectStr);
+ if (!aobj) {
+ /* Createthe directory */
+ aobj =yaffs_MknodDirectory(dev->xattrsDir, objectStr, 0, 0, 0);
+ }
+
+ if (!aobj) {
+ error =-ENOMEM;
+ gotocleanup;
+ }
+
+ /* See ifthis xattr already exists */
+ xobj =yaffs_FindObjectByName(aobj, xname);
+
+ if (xobj) { /*The xattr exists */
+ error =-EEXIST;
+ if (flags& XATTR_CREATE)
+ gotocleanup;
+
+ if (value== NULL) {
+ /*Remove the XATTR */
+ error= yaffs_Unlink(aobj, xname);
+ gotocleanup;
+ }
+
+ error =yaffs_xattr_set2(xobj, value, value_len);
+
+ } else { /*The xattr does not exist */
+ error =-ENODATA;
+ if (flags& XATTR_REPLACE)
+ gotocleanup;
+ error =0;
+ if (value== NULL) /* remove nonexistent attribute? */
+ gotocleanup;
+
+ xobj =yaffs_MknodFile(aobj, xname, 0, 0, 0);
+ if(!xobj) {
+ error= -ENOMEM;
+ gotocleanup;
+ }
+
+ error =yaffs_xattr_set2(xobj, value, value_len);
+ }
+
+cleanup:
+ yaffs_GrossUnlock(dev);
+
+ return error;
+}
+
+int __init
+init_yaffs_xattr(void)
+{
+ return 0;
+}
+
+void
+exit_yaffs_xattr(void)
+{
+}
diff --git a/fs/yaffs2/xattr.h b/fs/yaffs2/xattr.h
new file mode 100644
index 0000000..e359d0a
--- /dev/null
+++ b/fs/yaffs2/xattr.h
@@ -0,0 +1,95 @@
+/*
+ * Extended Attribute support for YAFFS
+ *
+ * Copyright (c) 2010 The Pennsylvania StateUniversity
+ * Systems and Internet Infrastructure SecurityLaboratory
+ *
+ * Created by William Enck <[email protected]>
+ * Acknowledgements:
+ * - General xattr handler structure taken from EXT2FS XATTR implementation
+ *
+ * This program is free software; you canredistribute it and/or modify
+ * it under the terms of the GNU General PublicLicense version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/xattr.h>
+
+/* Name indexes */
+#define YAFFS_XATTR_INDEX_USER 1
+#define YAFFS_XATTR_INDEX_POSIX_ACL_ACCESS 2
+#define YAFFS_XATTR_INDEX_POSIX_ACL_DEFAULT 3
+#define YAFFS_XATTR_INDEX_TRUSTED 4
+#define YAFFS_XATTR_INDEX_LUSTRE 5
+#define YAFFS_XATTR_INDEX_SECURITY 6
+
+#define YAFFS_OBJECTID_STRLEN 10 /* max length for the string version of anobject ID */
+
+#ifdef CONFIG_YAFFS_XATTR
+
+extern struct xattr_handler yaffs_xattr_user_handler;
+extern struct xattr_handler yaffs_xattr_trusted_handler;
+extern struct xattr_handleryaffs_xattr_security_handler;
+
+extern ssize_t yaffs_listxattr(struct dentry *, char*, size_t);
+
+extern int yaffs_xattr_get(struct inode *, int, constchar *, void *, size_t);
+extern int yaffs_xattr_set(struct inode *, int, constchar *, const void *, size_t, int);
+
+extern void yaffs_xattr_delete_inode (struct inode*);
+extern void yaffs_xattr_put_super(struct super_block*);
+
+extern int init_yaffs_xattr(void);
+extern void exit_yaffs_xattr(void);
+
+extern struct xattr_handler *yaffs_xattr_handlers[];
+
+# else /* CONFIG_YAFFS_XATTR */
+
+static inline int
+yaffs_xattr_get(struct inode *inode, int name_index,
+ constchar *name, const void *value, size_t size)
+{
+ return-EOPNOTSUPP;
+}
+
+static inline int
+yaffs_xattr_set(struct inode *inode, int name_index,const char *name,
+ constvoid *value, size_t size, int flags)
+{
+ return-EOPNOTSUPP;
+}
+
+static inline void
+yaffs_xattr_delete_inode(struct inode *inode)
+{
+}
+
+static inline void
+yaffs_xattr_put_super(struct super_block *sb)
+{
+}
+
+static inline int
+init_yaffs_xattr(void)
+{
+ return 0;
+}
+
+static inline void
+exit_yaffs_xattr(void)
+{
+}
+
+#define yaffs_xattr_handlers NULL
+
+#endif /* CONFIG_YAFFS_XATTR */
+
+#ifdef CONFIG_YAFFS_SECURITY
+extern int yaffs_init_security(struct inode *inode,struct inode *dir);
+#else
+static inline int yaffs_init_security(struct inode*inode, struct inode *dir)
+{
+ return 0;
+}
+#endif
diff --git a/fs/yaffs2/xattr_security.cb/fs/yaffs2/xattr_security.c
new file mode 100644
index 0000000..a275502
--- /dev/null
+++ b/fs/yaffs2/xattr_security.c
@@ -0,0 +1,81 @@
+/*
+ * Extended Attribute support for YAFFS
+ *
+ * Copyright (c) 2010 The Pennsylvania StateUniversity
+ * Systems and Internet Infrastructure SecurityLaboratory
+ *
+ * Created by William Enck <[email protected]>
+ * Acknowledgements:
+ * - General xattr handler structure taken from EXT2FS XATTR implementation
+ *
+ * This program is free software; you canredistribute it and/or modify
+ * it under the terms of the GNU General PublicLicense version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/security.h>
+#include "xattr.h"
+
+static size_t
+yaffs_xattr_security_list(struct inode *inode, char*list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ const size_ttotal_len = name_len + 1;
+
+ if (list&& total_len <= list_size) {
+ memcpy(list,name, name_len);
+ list[name_len]= '\0';
+ }
+ returntotal_len;
+}
+
+static int
+yaffs_xattr_security_get(struct inode *inode, constchar *name,
+ void*buffer, size_t size)
+{
+ if(strcmp(name, "") == 0)
+ return-EINVAL;
+ returnyaffs_xattr_get(inode, YAFFS_XATTR_INDEX_SECURITY, name,
+ buffer, size);
+}
+
+static int
+yaffs_xattr_security_set(struct inode *inode, constchar *name,
+ const void *value, size_t size, int flags)
+{
+ if(strcmp(name, "") == 0)
+ return-EINVAL;
+ returnyaffs_xattr_set(inode, YAFFS_XATTR_INDEX_SECURITY, name,
+ value, size, flags);
+}
+
+int
+yaffs_init_security(struct inode *inode, struct inode*dir)
+{
+ int err;
+ size_t len;
+ void *value;
+ char *name;
+
+ err =security_inode_init_security(inode, dir, &name, &value, &len);
+ if (err) {
+ if (err== -EOPNOTSUPP)
+ return0;
+ returnerr;
+ }
+ err =yaffs_xattr_set(inode, YAFFS_XATTR_INDEX_SECURITY, name,
+ value, len, 0);
+
+ kfree(name);
+ kfree(value);
+ return err;
+}
+
+struct xattr_handler yaffs_xattr_security_handler = {
+ .prefix =XATTR_SECURITY_PREFIX,
+ .list = yaffs_xattr_security_list,
+ .get = yaffs_xattr_security_get,
+ .set = yaffs_xattr_security_set,
+};
diff --git a/fs/yaffs2/xattr_trusted.cb/fs/yaffs2/xattr_trusted.c
new file mode 100644
index 0000000..247a6a3
--- /dev/null
+++ b/fs/yaffs2/xattr_trusted.c
@@ -0,0 +1,62 @@
+/*
+ * Extended Attribute support for YAFFS
+ *
+ * Copyright (c) 2010 The Pennsylvania StateUniversity
+ * Systems and Internet Infrastructure SecurityLaboratory
+ *
+ * Created by William Enck <[email protected]>
+ * Acknowledgements:
+ * - General xattr handler structure taken from EXT2FS XATTR implementation
+ *
+ * This program is free software; you canredistribute it and/or modify
+ * it under the terms of the GNU General PublicLicense version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/string.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include "xattr.h"
+
+static size_t
+yaffs_xattr_trusted_list(struct inode *inode, char*list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ const size_ttotal_len = name_len + 1;
+
+ if(!capable(CAP_SYS_ADMIN))
+ return 0;
+
+ if (list&& total_len <= list_size) {
+ memcpy(list,name, name_len);
+ list[name_len]= '\0';
+ }
+ returntotal_len;
+}
+
+static int
+yaffs_xattr_trusted_get(struct inode *inode, constchar *name,
+ void*buffer, size_t size)
+{
+ if(strcmp(name, "") == 0)
+ return-EINVAL;
+ returnyaffs_xattr_get(inode, YAFFS_XATTR_INDEX_TRUSTED, name,
+ buffer, size);
+}
+
+static int
+yaffs_xattr_trusted_set(struct inode *inode, constchar *name,
+ constvoid *value, size_t size, int flags)
+{
+ if(strcmp(name, "") == 0)
+ return-EINVAL;
+ returnyaffs_xattr_set(inode, YAFFS_XATTR_INDEX_TRUSTED, name,
+ value, size, flags);
+}
+
+struct xattr_handler yaffs_xattr_trusted_handler = {
+ .prefix =XATTR_TRUSTED_PREFIX,
+ .list = yaffs_xattr_trusted_list,
+ .get = yaffs_xattr_trusted_get,
+ .set = yaffs_xattr_trusted_set,
+};
diff --git a/fs/yaffs2/xattr_user.c b/fs/yaffs2/xattr_user.c
new file mode 100644
index 0000000..c4defd1
--- /dev/null
+++ b/fs/yaffs2/xattr_user.c
@@ -0,0 +1,71 @@
+/*
+ * Extended Attribute support for YAFFS
+ *
+ * Copyright (c) 2010 The Pennsylvania StateUniversity
+ * Systems and Internet Infrastructure SecurityLaboratory
+ *
+ * Created by William Enck <[email protected]>
+ * Acknowledgements:
+ * - General xattr handler structure taken from EXT2FS XATTR implementation
+ *
+ * This program is free software; you canredistribute it and/or modify
+ * it under the terms of the GNU General PublicLicense version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/string.h>
+#include <linux/fs.h>
+#include "xattr.h"
+
+static size_t
+yaffs_xattr_user_list(struct inode *inode, char*list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ const size_ttotal_len = name_len + 1;
+
+ /* TODO:enable this check like in EXT2?
+ if(!test_op(inode->i_sb, XATTR_USER))
+ return 0;
+ */
+
+ if (list&& total_len <= list_size) {
+ memcpy(list,name, name_len);
+ list[name_len]= '\0';
+ }
+ returntotal_len;
+}
+
+static int
+yaffs_xattr_user_get(struct inode *inode, const char*name,
+ void *buffer, size_t size)
+{
+ if(strcmp(name, "") == 0)
+ return-EINVAL;
+ /* TODO:enable this check like in EXT2?
+ if(!test_op(inode->i_sb, XATTR_USER))
+ return-EOPNOTSUPP;
+ */
+ returnyaffs_xattr_get(inode, YAFFS_XATTR_INDEX_USER, name,
+ buffer, size);
+}
+
+static int
+yaffs_xattr_user_set(struct inode *inode, const char*name,
+ constvoid *value, size_t size, int flags)
+{
+ if(strcmp(name, "") == 0)
+ return-EINVAL;
+ /* TODO:enable this check like in EXT2?
+ if(!test_op(inode->i_sb, XATTR_USER))
+ return-EOPNOTSUPP;
+ */
+ returnyaffs_xattr_set(inode, YAFFS_XATTR_INDEX_USER, name,
+ value, size, flags);
+}
+
+struct xattr_handler yaffs_xattr_user_handler = {
+ .prefix =XATTR_USER_PREFIX,
+ .list = yaffs_xattr_user_list,
+ .get = yaffs_xattr_user_get,
+ .set = yaffs_xattr_user_set,
+};
diff --git a/fs/yaffs2/yaffs_fs.cb/fs/yaffs2/yaffs_fs.c
index 47cae6f..b12bd55 100644
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -53,6 +53,7 @@ extern const char*yaffs_guts_c_version;
#include<linux/ctype.h>
#include"asm/div64.h"
+#include "xattr.h"
#if(LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
@@ -322,6 +323,12 @@ static const structfile_operations yaffs_file_operations = {
static conststruct inode_operations yaffs_file_inode_operations = {
.setattr = yaffs_setattr,
+#ifdef CONFIG_YAFFS_XATTR
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = yaffs_listxattr,
+ .removexattr = generic_removexattr,
+#endif
};
static conststruct inode_operations yaffs_symlink_inode_operations = {
@@ -341,6 +348,12 @@ static const structinode_operations yaffs_dir_inode_operations = {
.mknod = yaffs_mknod,
.rename = yaffs_rename,
.setattr = yaffs_setattr,
+#ifdef CONFIG_YAFFS_XATTR
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = yaffs_listxattr,
+ .removexattr = generic_removexattr,
+#endif
};
static conststruct file_operations yaffs_dir_operations = {
@@ -1858,6 +1871,7 @@ static struct super_block*yaffs_internal_read_super(int yaffsVersion,
sb->s_magic = YAFFS_MAGIC;
sb->s_op = &yaffs_super_ops;
sb->s_flags |= MS_NOATIME;
+ sb->s_xattr= yaffs_xattr_handlers;
if (!sb)
printk(KERN_INFO "yaffs: sb isNULL\n");
diff --git a/fs/yaffs2/yaffs_guts.cb/fs/yaffs2/yaffs_guts.c
index 05ff48d..320af83 100644
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -37,6 +37,10 @@ const char *yaffs_guts_c_version =
#include "yaffs_ecc.h"
+#ifdef CONFIG_YAFFS_XATTR
+# include "xattr.h"
+#endif
+
/*Robustification (if it ever comes about...) */
static voidyaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
@@ -5085,6 +5089,53 @@ int yaffs_FlushFile(yaffs_Object*in, int updateTime)
}
+#ifdef CONFIG_YAFFS_XATTR
+static int yaffs_DeleteXattrs(yaffs_Object *obj)
+{
+ int error =YAFFS_OK;
+ yaffs_Device*dev;
+ yaffs_Object*aobj = NULL; /* xattr directory object */
+ yaffs_Object*xobj = NULL; /* xattr data object */
+ structylist_head *i, *n;
+ charobjectStr[YAFFS_OBJECTID_STRLEN+1];
+
+
+ snprintf(objectStr,YAFFS_OBJECTID_STRLEN+1, "%d", obj->objectId);
+
+ dev =obj->myDev;
+ aobj =yaffs_FindObjectByName(dev->xattrsDir, objectStr);
+
+ if (!aobj) {
+ /* Nothing to do */
+ error = YAFFS_OK;
+ goto out;
+ }
+
+ /* Firstdelete all of the xattr value files */
+ ylist_for_each_safe(i,n, &aobj->variant.directoryVariant.children) {
+ int err;
+
+ if (!i)
+ continue;
+ xobj =ylist_entry(i, yaffs_Object, siblings);
+ err =yaffs_UnlinkObject(xobj);
+
+ if (err== YAFFS_FAIL) {
+ error= err;
+ }
+ }
+
+ /* Now deletethe directory itself */
+ if (error ==YAFFS_OK) {
+ /* Thedirectory is now empty and can be unlinked */
+ error =yaffs_UnlinkObject(aobj);
+ }
+
+out:
+ return error;
+}
+#endif
+
static intyaffs_DoGenericObjectDeletion(yaffs_Object *in)
{
@@ -5101,6 +5152,15 @@ static intyaffs_DoGenericObjectDeletion(yaffs_Object *in)
yaffs_DeleteChunk(in->myDev,in->hdrChunk, 1, __LINE__);
in->hdrChunk = 0;
+#ifdef CONFIG_YAFFS_XATTR
+ /* TODO: Howto handle failure? Ignore and cleanup on mount? */
+ /* No need toworry about circular dependencies, because XATTR file
+ * objectsshould never have an object ID directory in the XATTR
+ * directory
+ */
+ yaffs_DeleteXattrs(in);
+#endif
+
yaffs_FreeObject(in);
return YAFFS_OK;
@@ -7132,6 +7192,11 @@ static intyaffs_CreateInitialDirectories(yaffs_Device *dev)
dev->deletedDir =
yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
+#ifdef CONFIG_YAFFS_XATTR
+ dev->xattrsDir=
+ yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_XATTRS, S_IFDIR);
+#endif
+
dev->rootDir =
yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
YAFFS_ROOT_MODE | S_IFDIR);
@@ -7139,7 +7204,12 @@ static intyaffs_CreateInitialDirectories(yaffs_Device *dev)
yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
YAFFS_LOSTNFOUND_MODE |S_IFDIR);
+#ifdef CONFIG_YAFFS_XATTR
+ if(dev->lostNFoundDir && dev->rootDir &&dev->unlinkedDir && dev->deletedDir
+ &&dev->xattrsDir) {
+#else
if (dev->lostNFoundDir &&dev->rootDir && dev->unlinkedDir && dev->deletedDir) {
+#endif
yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
return YAFFS_OK;
}
diff --git a/fs/yaffs2/yaffs_guts.hb/fs/yaffs2/yaffs_guts.h
index a3b1102..b6b8bf5 100644
--- a/fs/yaffs2/yaffs_guts.h
+++ b/fs/yaffs2/yaffs_guts.h
@@ -80,6 +80,9 @@
#defineYAFFS_OBJECTID_LOSTNFOUND 2
#defineYAFFS_OBJECTID_UNLINKED 3
#defineYAFFS_OBJECTID_DELETED 4
+#ifdef CONFIG_YAFFS_XATTR
+# define YAFFS_OBJECTID_XATTRS 5
+#endif
/* Sseudoobject ids for checkpointing */
#defineYAFFS_OBJECTID_SB_HEADER 0x10
@@ -748,6 +751,9 @@ struct yaffs_DeviceStruct {
/* Stuff for background deletion and unlinkedfiles.*/
yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted fileslive. */
yaffs_Object *deletedDir; /* Directory where deleted objects are sentto disappear. */
+#ifdef CONFIG_YAFFS_XATTR
+ yaffs_Object*xattrsDir; /* Directory there xattrslive */
+#endif
yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
int nDeletedFiles; /* Count of files awaiting deletion;*/
int nUnlinkedFiles; /* Count of unlinked files. */