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.
+
+
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
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\
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
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;
//fill_empty_files_test("/yaffs2/");
//resize_stress_test("/yaffs2");
- overwrite_test("/yaffs2");
+ //overwrite_test("/yaffs2");
//long_name_test("/yaffs2");
//link_test0("/yaffs2");
//check_resize_gc_bug("/flash");
+ basic_xattr_test("/yaffs2");
+
return 0;
}
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_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\
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\
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\
#define YAFFSFS_N_HANDLES 100
-typedef struct {
+typedef struct yaffsfs_DeviceConfigurationStruct {
const YCHAR *prefix;
struct yaffs_DeviceStruct *dev;
} yaffsfs_DeviceConfiguration;
flashDev.param.initialiseNAND = yflash2_InitialiseNAND;
flashDev.param.markNANDBlockBad = yflash2_MarkNANDBlockBad;
flashDev.param.queryNANDBlock = yflash2_QueryNANDBlock;
+ flashDev.param.enableXattr = 1;
yaffs_initialise(yaffsfs_config);
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)
{
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);
int yaffs_inodecount(const YCHAR *path);
-void yaffs_initialise(yaffsfs_DeviceConfiguration *configList);
+
int yaffs_StartUp(void);
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
+#include "yaffsfs.h"
+
#endif
--- /dev/null
+#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/");
+}
/* #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.
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,
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 = {
.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 = {
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)
{
#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;
#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);
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);
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;
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;
}
* 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;
if (!in->fake ||
in == dev->rootDir || /* The rootDir should also be saved */
- force) {
+ force || xmod) {
yaffs_CheckGarbageCollection(dev,0);
yaffs_CheckObjectDetailsLoaded(in);
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;
break;
}
+ /* process any xattrib modifications */
+ if(xmod)
+ yaffs_ApplyXMod(dev, (char *)buffer, xmod);
+
+
/* Tags */
yaffs_InitialiseTags(&newTags);
in->serial++;
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;
!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;
#endif
}
- retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
+ retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >=
0) ? YAFFS_OK : YAFFS_FAIL;
}
} else {
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);
}
}
} else
- yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
+ yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
}
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);
}
}
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;
#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)
{
__u8 skipCheckpointRead;
__u8 skipCheckpointWrite;
+ int enableXattr; /* Enable xattribs */
+
/* NAND access functions (Must be set before calling YAFFS)*/
int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev,
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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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