X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=d3e877fe3d1275e0c072e649ae1da1227376f9f6;hp=3c1aa105f35fcf18f1cb73cbe06f4dd0e3e20c7d;hb=6014fce5c65757724aef9033f2a710da324f2523;hpb=87b33ecd1898c99b9aa2b0abcbb3e6002d6b3532 diff --git a/yaffs_guts.c b/yaffs_guts.c index 3c1aa10..d3e877f 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -41,7 +41,8 @@ static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, const u8 *buffer, int n_bytes, int use_reserve); - +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, + int buffer_size); /* Function to calculate chunk and offset */ @@ -648,15 +649,21 @@ static u16 yaffs_calc_name_sum(const YCHAR *name) return sum; } + void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name) { memset(obj->short_name, 0, sizeof(obj->short_name)); - if (name && + + if (name && !name[0]) { + yaffs_fix_null_name(obj, obj->short_name, + YAFFS_SHORT_NAME_LENGTH); + name = obj->short_name; + } else if (name && strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <= - YAFFS_SHORT_NAME_LENGTH) + YAFFS_SHORT_NAME_LENGTH) { strcpy(obj->short_name, name); - else - obj->short_name[0] = _Y('\0'); + } + obj->sum = yaffs_calc_name_sum(name); } @@ -973,7 +980,7 @@ static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk, return -1; } -static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, +int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, struct yaffs_ext_tags *tags) { /*Get the Tnode, then get the level 0 offset chunk offset */ @@ -3943,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; @@ -4586,15 +4657,16 @@ static int yaffs_create_initial_dir(struct yaffs_dev *dev) return YAFFS_FAIL; } -int yaffs_guts_initialise(struct yaffs_dev *dev) +/* Low level init. + * Typically only used by yaffs_guts_initialise, but also used by the + * Low level yaffs driver tests. + */ + +int yaffs_guts_ll_init(struct yaffs_dev *dev) { - int init_failed = 0; - unsigned x; - int bits; - 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, @@ -4603,10 +4675,8 @@ int yaffs_guts_initialise(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; @@ -4646,11 +4716,6 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) return YAFFS_FAIL; } - if (yaffs_init_nand(dev) != YAFFS_OK) { - yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); - return YAFFS_FAIL; - } - /* Sort out space for inband tags, if required */ if (dev->param.inband_tags) dev->data_bytes_per_chunk = @@ -4668,7 +4733,50 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) return YAFFS_FAIL; } - /* Finished with most checks. Further checks happen later on too. */ + 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; +} + + +int yaffs_guts_initialise(struct yaffs_dev *dev) +{ + int init_failed = 0; + unsigned x; + int bits; + + if(yaffs_guts_ll_init(dev) != YAFFS_OK) + return YAFFS_FAIL; + + if (dev->is_mounted) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); + return YAFFS_FAIL; + } dev->is_mounted = 1; @@ -4992,6 +5100,8 @@ int yaffs_get_n_free_chunks(struct yaffs_dev *dev) return n_free; } + + /* * Marshalling functions to get loff_t file sizes into and out of * object headers. @@ -5014,3 +5124,23 @@ loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh) return retval; } + + +void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]) +{ + int i; + struct yaffs_block_info *bi; + int s; + + for(i = 0; i < 10; i++) + bs[i] = 0; + + for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + bi = yaffs_get_block_info(dev, i); + s = bi->block_state; + if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN) + bs[0]++; + else + bs[s]++; + } +}