yaffs: Fix yaffsfs xattr error handling, add yaffs_lsetxattr and friends
[yaffs2.git] / yaffs_guts.c
index d067d1d03d53552efbff6d9bd16e84f83a86f71d..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,11 +87,11 @@ 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_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
-                       int chunkOffset, int *limit);
 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
 
 static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
@@ -615,7 +626,8 @@ static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh,
 }
 
 
-
+#if 0
+/* Not being used, but don't want to throw away yet */
 static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
                                        __u32 level, int chunkOffset)
 {
@@ -661,6 +673,7 @@ static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
 
 }
 
+#endif
 
 static void yaffs_VerifyFile(yaffs_Object *obj)
 {
@@ -1713,9 +1726,10 @@ static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
        return -1;
 }
 
-
+#if 0
+/* Experimental code not being used yet. Might speed up file deletion */
 /* DeleteWorker scans backwards through the tnode tree and deletes all the
- * chunks and tnodes in the file
+ * chunks and tnodes in the file.
  * Returns 1 if the tree was deleted.
  * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
  */
@@ -1807,6 +1821,8 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
 
 }
 
+#endif
+
 static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
 {
        yaffs_BlockInfo *theBlock;
@@ -2516,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;
@@ -2624,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;
        }
 
@@ -4045,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;
@@ -4071,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);
@@ -4088,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;
@@ -4158,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++;
@@ -5466,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;
@@ -5506,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;
@@ -5550,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 {
@@ -5621,7 +5642,7 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
 int yaffs_DeleteFile(yaffs_Object *in)
 {
        int retVal = YAFFS_OK;
-       int deleted = in->deleted;
+       int deleted; /* Need to cache value on stack if in is freed */
        yaffs_Device *dev = in->myDev;
 
        if (dev->param.disableSoftDelete || dev->param.isYaffs2)
@@ -5634,6 +5655,8 @@ int yaffs_DeleteFile(yaffs_Object *in)
                if (!in->unlinked)
                        retVal = yaffs_UnlinkFileIfNeeded(in);
 
+               deleted = in->deleted;
+
                if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
                        in->deleted = 1;
                        deleted = 1;
@@ -6473,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);
                }
@@ -7307,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)
@@ -7330,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);
        }
 }
 
@@ -7661,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;
 
@@ -7694,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)
 {