All of lore.kernel.org
 help / color / mirror / Atom feed
From: "ÂíÔÆ" <sx_yunma@bit.edu.cn>
To: linux-mtd@lists.infradead.org
Subject: [PATCH] XATTR support in JFFS2
Date: Mon, 22 Aug 2005 12:41:18 +0800	[thread overview]
Message-ID: <324685678.22043@bit.edu.cn> (raw)

[-- Attachment #1: Type: text/plain, Size: 412 bytes --]

Hi!
 
I've implemented the extended attributes for JFFS2. The implementation mechanism
is simple, but it can work:). This implementation support standard extended
attributes system call, such as setxattr, getxattr .... but does not support ACL.
 
The patch is based on Linux-2.6.10
 
Comments are welcome...
 
Signed-off-by: Yun Ma <yunma@sc.mcel.mot.com>
 
 
===========================
Best Regards 

Yun Ma



[-- Attachment #2: patch-jffs2-xattr.patch --]
[-- Type: text/plain, Size: 18878 bytes --]

diff -uNr linux-2.6.10.mxc/fs/jffs2/file.c linux-2.6.10.jffs2/fs/jffs2/file.c
--- linux-2.6.10.mxc/fs/jffs2/file.c	2005-08-19 15:40:26.000000000 +0800
+++ linux-2.6.10.jffs2/fs/jffs2/file.c	2005-08-19 15:48:40.000000000 +0800
@@ -20,6 +20,9 @@
 #include <linux/highmem.h>
 #include <linux/crc32.h>
 #include <linux/jffs2.h>
+#ifdef CONFIG_JFFS2_FS_XATTR
+#include <linux/jffs2_xattr.h>
+#endif
 #include "nodelist.h"
 
 extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
@@ -55,6 +58,12 @@
 
 struct inode_operations jffs2_file_inode_operations =
 {
+#ifdef CONFIG_JFFS2_FS_XATTR
+        .setxattr = jffs2_setxattr,
+        .getxattr = jffs2_getxattr,
+        .listxattr = jffs2_listxattr,
+        .removexattr = jffs2_removexattr,
+#endif
 	.setattr =	jffs2_setattr
 };
 
diff -uNr linux-2.6.10.mxc/fs/jffs2/Makefile linux-2.6.10.jffs2/fs/jffs2/Makefile
--- linux-2.6.10.mxc/fs/jffs2/Makefile	2005-08-19 15:40:26.000000000 +0800
+++ linux-2.6.10.jffs2/fs/jffs2/Makefile	2005-08-19 15:44:39.000000000 +0800
@@ -11,6 +11,7 @@
 jffs2-y	+= symlink.o build.o erase.o background.o fs.o writev.o
 jffs2-y	+= super.o
 
+jffs2-$(CONFIG_JFFS2_FS_XATTR)	+= xattr.o
 jffs2-$(CONFIG_JFFS2_FS_NAND)	+= wbuf.o
 jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
diff -uNr linux-2.6.10.mxc/fs/jffs2/nodelist.c linux-2.6.10.jffs2/fs/jffs2/nodelist.c
--- linux-2.6.10.mxc/fs/jffs2/nodelist.c	2005-08-19 15:40:26.000000000 +0800
+++ linux-2.6.10.jffs2/fs/jffs2/nodelist.c	2005-08-19 15:47:12.000000000 +0800
@@ -173,6 +173,7 @@
 				goto free_out;
 			}
 			/* sanity check */
+			#ifndef CONFIG_JFFS2_FS_XATTR
 			if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) {
 				printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n",
 				       ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
@@ -180,6 +181,7 @@
 				spin_lock(&c->erase_completion_lock);
 				continue;
 			}
+			#endif
 			if (je32_to_cpu(node.d.version) > *highest_version)
 				*highest_version = je32_to_cpu(node.d.version);
 			if (ref_obsolete(ref)) {
diff -uNr linux-2.6.10.mxc/fs/jffs2/xattr.c linux-2.6.10.jffs2/fs/jffs2/xattr.c
--- linux-2.6.10.mxc/fs/jffs2/xattr.c	1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.10.jffs2/fs/jffs2/xattr.c	2005-08-19 16:17:29.000000000 +0800
@@ -0,0 +1,467 @@
+/*
+ *
+ * Copyright 2005 Motorola, Inc. All Rights Reserved.
+ * 
+ * Created by Ma yun <yunma@sc.mcel.mot.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/crc32.h>
+#include <linux/jffs2.h>
+#include <linux/jffs2_fs_i.h>
+#include <linux/jffs2_fs_sb.h>
+#include <linux/jffs2_xattr.h>
+#include <linux/mtd/mtd.h>
+#include <linux/time.h>
+#include "nodelist.h"
+
+
+struct xattr_buffer {
+	int size;				/* the size of current use  buffer */
+	struct jffs2_xattr_list *xattr;		/* buffer containing EAs list */
+};
+
+static int ea_get(struct dentry *parent, struct inode *inode, struct xattr_buffer *ea_buf, int min_size)
+{
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode), *p;
+	struct jffs2_raw_dirent	findnode;
+	struct jffs2_raw_node_ref *raw = NULL;
+	struct jffs2_full_dirent *fd_list = NULL;
+	size_t readlen;
+	int size;
+	uint32_t offset = 0;	
+	uint32_t ino = f->inocache->ino;
+	int	mem_size = 0;
+	int	ret = 0;	
+	int	n_version =0 ;
+
+	memset(&findnode, 0, sizeof(findnode));
+	/* lookup the dirent list and find raw dirent*/
+
+	p = JFFS2_INODE_INFO(parent->d_inode);
+	down(&p->sem);
+	for(fd_list = p->dents; fd_list; fd_list = fd_list->next){
+		if (fd_list->ino == ino && fd_list->version >= n_version) n_version = fd_list->version;
+	}
+
+	for(fd_list = p->dents; fd_list; fd_list = fd_list->next){
+                if (fd_list->ino == ino && fd_list->version == n_version) break;
+        }
+	
+	if (fd_list->ino == ino) {
+		for(raw = fd_list->raw; raw && raw->next_in_ino; raw = raw->next_in_ino){
+			offset = ref_offset(raw);
+			ret = jffs2_flash_read(c, offset, sizeof(findnode), &readlen,(char *)&findnode);
+			if (readlen != sizeof(findnode) || ret) {
+				up(&p->sem);
+				printk(KERN_WARNING"Error reading node from 0x%08x: %d\n",offset,ret);
+				return ret;
+			}
+			if ((je32_to_cpu(findnode.ino) == ino) && je16_to_cpu(findnode.nodetype) == JFFS2_NODETYPE_DIRENT) break;
+		}
+	} else {
+		up(&p->sem);
+		printk(KERN_WARNING"ea_get: can not find the file" );
+		return -1;
+	}
+	up(&p->sem);
+	/* actually, we should check CRC */
+	
+	/* end of CRC check */
+	size = je32_to_cpu(findnode.totlen) - (findnode.nsize) - sizeof(findnode);
+	mem_size = max(size, min_size);
+	if (!mem_size) {
+		ea_buf->size = 0;
+		return 0;
+	} else {
+		/* allo`cate a buffer to work with */
+		ea_buf->size = mem_size;
+		ea_buf->xattr = kmalloc(mem_size, GFP_KERNEL);
+		
+		if (ea_buf->xattr == NULL) {
+			return -ENOMEM;
+		}
+		/* copy rd EAs to ea_buf */
+		offset = ref_offset(raw);
+		ret = jffs2_flash_read(c, offset + sizeof(findnode) + findnode.nsize, size, &readlen, (char *)ea_buf->xattr);
+		if (ret|| readlen != size){
+			printk(KERN_WARNING"Error reading node form 0x%08x: %d\n", offset, ret);
+			return ret;
+		}
+		return size;	
+	} 	
+}
+
+
+static int ea_put(struct dentry *parent, struct inode *inode, struct xattr_buffer *ea_buf, int new_size)
+{
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);	
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode), *p;
+	struct jffs2_raw_dirent *rd, findnode;
+        struct jffs2_raw_node_ref *raw;
+        struct jffs2_full_dirent *fd, *fd_list = NULL;
+	uint32_t direntlen, offset, alloclen, readlen;
+	int ret = 0;
+	char *name, *write_buf = NULL;
+	int namelen = 0;
+	uint32_t ino = f->inocache->ino;
+	int     n_version =0 ;
+
+	memset(&findnode, 0, sizeof(findnode));
+	/* lookup the dirent list and find raw dirent*/
+        p = JFFS2_INODE_INFO(parent->d_inode);
+       	down(&p->sem); 
+	
+	for(fd_list = p->dents; fd_list; fd_list = fd_list->next){
+                if (fd_list->ino == ino && fd_list->version >= n_version) n_version = fd_list->version;
+        }
+
+	for(fd_list = p->dents; fd_list; fd_list = fd_list->next)
+                if (fd_list->ino == ino && fd_list->version == fd_list->version) break;
+
+        if (fd_list->ino == ino){
+                for(raw = fd_list->raw; raw && raw->next_in_ino; raw = raw->next_in_ino) {
+                        offset = ref_offset(raw);
+                        ret = jffs2_flash_read(c, offset, sizeof(findnode), &readlen,(char *)&findnode);
+                        if (ret||readlen != sizeof(findnode)) {
+				up(&p->sem);
+                                printk(KERN_WARNING"Error reading node from 0x%08x: %d\n",offset,ret);
+                                return ret;
+                        }
+                        if ((je32_to_cpu(findnode.ino) == ino) && je16_to_cpu(findnode.nodetype) == JFFS2_NODETYPE_DIRENT) break;
+                }
+        } else {
+		up(&p->sem);
+                printk(KERN_WARNING"ea_put: can not find the file" );
+                return -1;
+        }
+	up(&p->sem);
+	
+	namelen = findnode.nsize;
+
+	/* alloc write_buf for write flash */	
+	write_buf  = kmalloc(namelen + new_size, GFP_KERNEL);
+        if (!write_buf) {
+                return -ENOMEM;
+        }
+	/* get the name in write_buf */
+        ret = jffs2_flash_read(c, offset + sizeof(findnode), findnode.nsize, &readlen, write_buf);        
+	if (ret||readlen != findnode.nsize){
+		printk(KERN_WARNING"Error reading node form 0x%08x: %d\n", offset, ret);
+		return ret;
+	}
+	/* get the name in "name" */
+	name = kmalloc(namelen + 1, GFP_KERNEL);
+	if (!name) {
+		if (write_buf)
+			kfree(write_buf);
+		return -ENOMEM;
+	}
+	memcpy(name, write_buf, namelen);
+	/* find the space for write */
+	direntlen = sizeof(findnode) + namelen + new_size;
+	ret = jffs2_reserve_space(c, direntlen, &offset, &alloclen, ALLOC_NORMAL);
+	if (ret) {
+		return ret;
+	}
+	/* alloc the raw_dirent cache */
+	rd = jffs2_alloc_raw_dirent();
+	if (!rd) {
+		if (write_buf)
+			kfree(write_buf);
+		if (name)
+			kfree(name);
+		return -ENOMEM;
+	}
+
+	down(&p->sem);
+	
+	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd->totlen = cpu_to_je32(direntlen);
+	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node) - 4));
+	
+	rd->pino = cpu_to_je32(p->inocache->ino);
+	rd->version = cpu_to_je32(++p->highest_version);
+	rd->ino	= findnode.ino;
+	rd->mctime = cpu_to_je32(get_seconds());
+	rd->nsize = namelen;
+	rd->unused[0] = ea_buf->size;
+	/* fix me*/
+	memcpy(&(write_buf[namelen]), ea_buf->xattr, new_size);
+	rd->type = findnode.type;
+	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd) - 8));
+	rd->name_crc = cpu_to_je32(crc32(0, write_buf, namelen));
+	
+	fd = jffs2_write_dirent(c, p, rd, write_buf, namelen + new_size, offset, ALLOC_NORMAL);
+	/* restore the name */
+	fd->nhash = full_name_hash(name, namelen);
+	fd->name[namelen] = 0;
+	if (IS_ERR(fd)) {
+		if (write_buf) 
+			kfree(write_buf);
+		if (name)
+			kfree(name);
+		jffs2_free_raw_dirent(rd);
+		jffs2_complete_reservation(c);
+		up(&p->sem);
+		return PTR_ERR(fd);
+	}
+	jffs2_add_fd_to_list(c, fd, &p->dents);
+	jffs2_complete_reservation(c);
+	jffs2_free_raw_dirent(rd);
+	up(&p->sem);
+	if (write_buf) 
+		kfree(write_buf);
+	if (name)
+		kfree(name);
+
+	return 0;
+}
+
+
+static void ea_release(struct xattr_buffer *ea_buf)
+{
+	if (ea_buf->size) 
+		kfree(ea_buf->xattr);
+}
+ssize_t jffs2_getxattr(struct dentry *dentry, const char *name, void *data, size_t buf_size)
+{
+	struct inode *inode = dentry->d_inode;
+	struct dentry *parent;
+	struct jffs2_xattr_list *ealist;
+	struct jffs2_xattr	*ea;
+	struct xattr_buffer	ea_buf;
+	int xattr_size;
+	ssize_t	size;
+	int namelen = strlen(name);
+	char *value;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	D1(printk(KERN_DEBUG"jffs2_getxattr: name=%s, buffer=%p, buffer_size=%ld",name,data,(long)buf_size));
+
+//	down_read(&JFFS2_INODE_INFO(inode)->xattr_sem);
+	parent = dentry->d_parent;
+	xattr_size = ea_get(parent, inode, &ea_buf, 0);
+	if (xattr_size < 0) {
+		size = xattr_size;
+		goto out;
+	}
+
+	if (xattr_size == 0) {
+		goto not_found;
+	}
+
+	ealist = (struct jffs2_xattr_list *)ea_buf.xattr;
+	
+	/* Find the named attribute*/
+	for (ea=FIRST_XATTR(ealist); ea < END_XATTR(ealist,xattr_size); ea = NEXT_XATTR(ea))
+		if ((namelen == ea->namelen) &&
+			memcmp(name,ea->name,namelen)==0) {
+		/* Found */
+		size = ea->valuelen;
+		if (!data)
+			goto release;
+		else if (size > buf_size) {
+			size = -ERANGE;
+			goto release;
+		}
+		value = ((char *)&ea->name) + ea->namelen + 1;
+		memcpy(data,value,size);
+		goto release;
+	}
+not_found:
+	data = NULL;
+	size = -ENODATA;
+release:
+	ea_release(&ea_buf);
+out:
+//	up_read(&JFFS2_INODE_INFO(inode)->xattr_sem);
+	return size;
+}
+
+int jffs2_setxattr(struct dentry *dentry, const char *name, const void *value, size_t value_len, int flags)
+{
+	struct inode *inode = dentry->d_inode;
+	struct dentry *parent;
+	struct jffs2_xattr_list *ealist;
+	struct jffs2_xattr	*ea, *old_ea = NULL, *next_ea = NULL;			
+	struct xattr_buffer	ea_buf;
+	int found=0;
+	int xattr_size = 0;
+	int namelen = strlen(name);
+	int old_ea_size = 0;
+	int new_size;			/* the size of new EAs */
+	int length;
+	int ret;
+	
+	if (value == NULL || value_len == 0) {
+		value = "";
+		value_len = 0;
+	}
+	
+	parent = dentry->d_parent;
+	/* read the inode's EAs */
+	xattr_size = ea_get(parent, inode, &ea_buf, 0);
+	if (xattr_size < 0) {
+		ret = xattr_size;
+		goto out;
+	}
+
+  again:
+	ealist = (struct jffs2_xattr_list *)ea_buf.xattr;
+	new_size = sizeof(struct jffs2_xattr_list);
+
+	if (xattr_size) {
+		for (ea = FIRST_XATTR(ealist); ea < END_XATTR(ealist,xattr_size); ea = NEXT_XATTR(ea)) {
+			if ((namelen == ea->namelen) &&
+				(memcmp(name, ea->name,namelen) == 0)) {
+				found = 1;
+				if (flags & XATTR_CREATE) {
+					ret = -EEXIST;
+					goto release;
+				}
+				old_ea = ea;
+				old_ea_size = JFFS2_XATTR_SIZE(ea);
+				next_ea = NEXT_XATTR(ea);
+			} else 
+				new_size += JFFS2_XATTR_SIZE(ea);
+		}
+	}
+	
+	if (!found) {
+		if (flags & XATTR_REPLACE) {
+			ret = -ENODATA;
+			goto release;
+		}
+		if (value == NULL) {
+			ret = 0;
+			goto release;
+		}
+	}
+	if (value && value_len)
+		new_size += sizeof(struct jffs2_xattr) + namelen + 1 + value_len;
+	
+	/* compare with the size of current buffer */
+	if (new_size > ea_buf.size) {
+		/*
+		 * We need to reallocate more space for merged ea list
+		 */
+		ea_release(&ea_buf);
+		xattr_size = ea_get(parent, inode, &ea_buf, new_size);
+		if (xattr_size < 0) {
+			ret = xattr_size;
+			goto out;
+		} 
+		goto again;	
+	}
+
+	/* remove the old ea of the same name */
+	if (found) {
+		length = (char *)END_XATTR(ealist,xattr_size) - (char *)next_ea;
+		if (length > 0)
+			memmove(old_ea,next_ea,length);
+		xattr_size -= old_ea_size;
+	}
+	/* add new EA to the end */
+	if (value && value_len) {
+		ea = (struct jffs2_xattr *)((char *)ealist + xattr_size);
+		ea->namelen = namelen;
+		ea->valuelen = value_len;
+		memcpy(ea->name, name, namelen);
+		ea->name[namelen] = 0;
+		if (value_len)
+			memcpy(ea->name + namelen + 1, value, value_len);
+		xattr_size += JFFS2_XATTR_SIZE(ea);		
+	}
+	/* DEGUG*/
+	if (new_size != xattr_size) {
+		printk(KERN_ERR"jffs2_setxattr: xattr_size = %d, new_size = %d\n", xattr_size, new_size);
+		ret = -EINVAL;
+		goto release;
+	}
+	if (new_size == sizeof(struct jffs2_xattr_list))
+		new_size = 0;
+	
+	ret = ea_put(parent, inode, &ea_buf, new_size);
+	goto out;
+   release:
+	ea_release(&ea_buf);
+   out:
+	//up_write(&JFFS2_INODE_INFO(inode)->xattr_sem);
+	return ret;
+}
+
+ssize_t jffs2_listxattr(struct dentry *dentry, char *data, size_t buf_size)
+{
+	struct inode *inode = dentry->d_inode;
+	struct dentry *parent;
+	char *buffer;
+	ssize_t size = 0;
+	int xattr_size;
+	struct jffs2_xattr_list *ealist;
+	struct jffs2_xattr *ea;
+	struct xattr_buffer ea_buf;
+	
+	memset(data, 0, buf_size);
+	//down_read(&JFFS2_INODE_INFO(inode)->xattr_sem);
+	parent = dentry->d_parent;
+	xattr_size = ea_get(parent, inode, &ea_buf, 0);
+	if (xattr_size < 0) {
+		size = xattr_size;
+		goto out;
+	}
+	if (xattr_size == 0) {
+		goto release;
+	}
+	
+	ealist = (struct jffs2_xattr_list *)ea_buf.xattr;
+	
+	for (ea = FIRST_XATTR(ealist); ea < END_XATTR(ealist, xattr_size); ea = NEXT_XATTR(ea))
+		size += ea->namelen +1;
+
+	if (!data) 
+		goto release;
+
+	if (size > buf_size) {
+		size = -ERANGE;
+		goto release;
+	}
+	buffer = data;
+	for (ea = FIRST_XATTR(ealist); ea < END_XATTR(ealist, xattr_size); ea = NEXT_XATTR(ea)) {
+		memcpy(buffer, ea->name, ea->namelen);
+		buffer[ea->namelen] = '\\';
+		buffer += ea->namelen +1;
+	}
+   release:
+	ea_release(&ea_buf);
+   out:
+//	up_read(&JFFS2_INODE_INFO(inode)->xattr_sem);
+	return size;
+}
+
+int jffs2_removexattr(struct dentry *dentry, const char *name)
+{
+	return jffs2_setxattr(dentry, name, NULL, 0, XATTR_REPLACE);
+}  
diff -uNr linux-2.6.10.mxc/fs/Kconfig linux-2.6.10.jffs2/fs/Kconfig
--- linux-2.6.10.mxc/fs/Kconfig	2005-08-19 15:40:26.000000000 +0800
+++ linux-2.6.10.jffs2/fs/Kconfig	2005-08-19 15:50:52.000000000 +0800
@@ -1201,6 +1201,12 @@
 	  Further information on the design and implementation of JFFS2 is
 	  available at <http://sources.redhat.com/jffs2/>.
 
+config JFFS2_FS_XATTR
+	bool "JFFS2 extended attributes"
+	depends on JFFS2_FS
+	help
+	 JFFS2 extended attributes
+
 config JFFS2_FS_DEBUG
 	int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)"
 	depends on JFFS2_FS
diff -uNr linux-2.6.10.mxc/include/linux/jffs2_xattr.h linux-2.6.10.jffs2/include/linux/jffs2_xattr.h
--- linux-2.6.10.mxc/include/linux/jffs2_xattr.h	1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.10.jffs2/include/linux/jffs2_xattr.h	2005-08-19 16:20:18.000000000 +0800
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright 2005 Motorola, Inc. All Rights Reserved.
+ *
+ * Created by Ma yun <yunma@sc.mcel.mot.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef  _JFFS2_XATTR
+#define  _JFFS2_XATTR
+
+/* jffs2_xattr describe the on-disk format of the extended attributes.
+ *
+ */
+struct jffs2_xattr {
+	uint8_t namelen;	/* Length of name */
+	uint8_t valuelen;	/* Length of value */
+	char name[0];		/* Attribute name (include null-terminator)*/
+				/* Attribute Valude immediately follows name */
+}__attribute__((packed));
+
+struct jffs2_xattr_list {
+	struct jffs2_xattr xattr[0];	/* EAs list */
+}__attribute__((packed));
+
+
+/* 
+ * Some macros for dealing with variable length EA lists.
+ */
+#define JFFS2_XATTR_SIZE(xattr)	\
+	(sizeof(struct jffs2_xattr) + (xattr)->namelen + 1 + \
+	(xattr)->valuelen)
+#define NEXT_XATTR(xattr)	\
+	((struct jffs2_xattr *)(((char *)(xattr)) + (JFFS2_XATTR_SIZE(xattr))))
+#define FIRST_XATTR(xattr_list)	\
+	((xattr_list)->xattr)
+#define END_XATTR(xattr_list,size)	\
+	((struct jffs2_xattr *)(((char *)(xattr_list)) + size))
+
+extern int jffs2_setxattr(struct dentry *, const char *, const void *, size_t, int);
+extern ssize_t jffs2_getxattr(struct dentry *, const char *, void *, size_t);
+extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
+extern int jffs2_removexattr(struct dentry *, const char *);
+
+#endif
+

             reply	other threads:[~2005-08-22  4:57 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-08-22  4:41 ÂíÔÆ [this message]
  -- strict thread matches above, loose matches on Subject: below --
2005-08-23  3:24 [PATCH] XATTR support in JFFS2 Ma Yun
2005-08-23 12:39 ` Jörn Engel
2005-08-24 11:08 Ma Yun
2005-08-24 16:34 ` Jörn Engel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=324685678.22043@bit.edu.cn \
    --to=sx_yunma@bit.edu.cn \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.