Change the object type if it turns out to be wrong during a scan
[yaffs2.git] / yaffs_guts.c
index 8507c2d94a7b128af414c7c0ad572716d73b163d..d3e877fe3d1275e0c072e649ae1da1227376f9f6 100644 (file)
@@ -3950,6 +3950,70 @@ int yaffs_del_obj(struct yaffs_obj *obj)
        return ret_val;
 }
 
+
+static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
+                                  struct yaffs_obj *to_dir)
+{
+       struct yaffs_obj *obj;
+       struct list_head *lh;
+       struct list_head *n;
+
+       list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
+               obj = list_entry(lh, struct yaffs_obj, siblings);
+               yaffs_add_obj_to_dir(to_dir, obj);
+       }
+}
+
+struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
+                                  enum yaffs_obj_type type)
+{
+       /* Tear down the old variant */
+       switch (obj->variant_type) {
+       case YAFFS_OBJECT_TYPE_FILE:
+               /* Nuke file data */
+               yaffs_resize_file(obj, 0);
+               yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
+               obj->variant.file_variant.top = NULL;
+               break;
+       case YAFFS_OBJECT_TYPE_DIRECTORY:
+               /* Put the children in lost and found. */
+               yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
+               if (!list_empty(&obj->variant.dir_variant.dirty))
+                       list_del_init(&obj->variant.dir_variant.dirty);
+               break;
+       case YAFFS_OBJECT_TYPE_SYMLINK:
+               /* Nuke symplink data */
+               kfree(obj->variant.symlink_variant.alias);
+               obj->variant.symlink_variant.alias = NULL;
+               break;
+       case YAFFS_OBJECT_TYPE_HARDLINK:
+               list_del_init(&obj->hard_links);
+               break;
+       default:
+               break;
+       }
+
+       memset(&obj->variant, 0, sizeof(obj->variant));
+
+       /*Set up new variant if the memset is not enough. */
+       switch (type) {
+       case YAFFS_OBJECT_TYPE_DIRECTORY:
+               INIT_LIST_HEAD(&obj->variant.dir_variant.children);
+               INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
+               break;
+       case YAFFS_OBJECT_TYPE_FILE:
+       case YAFFS_OBJECT_TYPE_SYMLINK:
+       case YAFFS_OBJECT_TYPE_HARDLINK:
+       default:
+               break;
+       }
+
+       obj->variant_type = type;
+
+       return obj;
+
+}
+
 static int yaffs_unlink_worker(struct yaffs_obj *obj)
 {
        int del_now = 0;
@@ -4602,9 +4666,7 @@ int yaffs_guts_ll_init(struct yaffs_dev *dev)
 {
 
 
-       yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_guts_initialise()");
-
-       /* Check stuff that must be set */
+       yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
 
        if (!dev) {
                yaffs_trace(YAFFS_TRACE_ALWAYS,
@@ -4613,10 +4675,8 @@ int yaffs_guts_ll_init(struct yaffs_dev *dev)
                return YAFFS_FAIL;
        }
 
-       if (dev->is_mounted) {
-               yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
-               return YAFFS_FAIL;
-       }
+       if (dev->ll_init)
+               return YAFFS_OK;
 
        dev->internal_start_block = dev->param.start_block;
        dev->internal_end_block = dev->param.end_block;
@@ -4673,6 +4733,33 @@ int yaffs_guts_ll_init(struct yaffs_dev *dev)
                return YAFFS_FAIL;
        }
 
+       if (yaffs_init_nand(dev) != YAFFS_OK) {
+               yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
+               return YAFFS_FAIL;
+       }
+
+       return YAFFS_OK;
+}
+
+
+int yaffs_format_dev(struct yaffs_dev *dev)
+{
+       int i;
+       enum yaffs_block_state state;
+       u32 dummy;
+
+       if(yaffs_guts_ll_init(dev) != YAFFS_OK)
+               return YAFFS_FAIL;
+
+       if(dev->is_mounted)
+               return YAFFS_FAIL;
+
+       for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+               yaffs_query_init_block_state(dev, i, &state, &dummy);
+               if (state != YAFFS_BLOCK_STATE_DEAD)
+                       yaffs_erase_block(dev, i);
+       }
+
        return YAFFS_OK;
 }
 
@@ -4686,9 +4773,8 @@ int yaffs_guts_initialise(struct yaffs_dev *dev)
        if(yaffs_guts_ll_init(dev) != YAFFS_OK)
                return YAFFS_FAIL;
 
-
-       if (yaffs_init_nand(dev) != YAFFS_OK) {
-               yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
+       if (dev->is_mounted) {
+               yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
                return YAFFS_FAIL;
        }
 
@@ -5015,40 +5101,6 @@ int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
 }
 
 
-int yaffs_format_dev(struct yaffs_dev *dev)
-{
-       int i;
-       enum yaffs_block_state state;
-       u32 dummy;
-
-       if(dev->is_mounted)
-               return YAFFS_FAIL;
-
-       /*
-       * The runtime variables might not have been set up,
-       * so set up what we need.
-       */
-       dev->internal_start_block = dev->param.start_block;
-       dev->internal_end_block = dev->param.end_block;
-       dev->block_offset = 0;
-       dev->chunk_offset = 0;
-
-       if (dev->param.start_block == 0) {
-               dev->internal_start_block = dev->param.start_block + 1;
-               dev->internal_end_block = dev->param.end_block + 1;
-               dev->block_offset = 1;
-               dev->chunk_offset = dev->param.chunks_per_block;
-       }
-
-       for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
-               yaffs_query_init_block_state(dev, i, &state, &dummy);
-               if (state != YAFFS_BLOCK_STATE_DEAD)
-                       yaffs_erase_block(dev, i);
-       }
-
-       return YAFFS_OK;
-}
-
 
 /*
  * Marshalling functions to get loff_t file sizes into and out of