ipmi_fru_set_field_string_rebuild(struct ipmi_intf * intf, uint8_t fruId,
											struct fru_info fru, struct fru_header header,
											uint8_t f_type, uint8_t f_index, char *f_string)
{
	int i = 0;
	uint8_t *fru_data_old = NULL;
	uint8_t *fru_data_new = NULL;
	uint8_t *fru_area = NULL;
	uint32_t fru_field_offset, fru_field_offset_tmp;
	uint32_t fru_section_len, header_offset;
	uint32_t chassis_offset, board_offset, product_offset;
	uint32_t chassis_len, board_len, product_len, product_len_new;
	int      num_byte_change = 0, padding_len = 0;
	uint32_t counter;
	unsigned char cksum;
	int rc = 1;

	fru_data_old = calloc( fru.size, sizeof(uint8_t) );

	fru_data_new = malloc( fru.size );

	if (!fru_data_old || !fru_data_new) {
		printf("Out of memory!\n");
		rc = -1;
		goto ipmi_fru_set_field_string_rebuild_out;
	}

	/*************************
	1) Read ALL FRU */
	printf("Read All FRU area\n");
	printf("Fru Size       : %u bytes\n", fru.size);

	/* Read current fru data */
	read_fru_area(intf ,&fru, fruId, 0, fru.size , fru_data_old);

	#ifdef DBG_RESIZE_FRU
	printf("Copy to new FRU\n");
	#endif

	/*************************
	2) Copy all FRU to new FRU */
	memcpy(fru_data_new, fru_data_old, fru.size);

	/* Build location of all modifiable components */
	chassis_offset = (header.offset.chassis * 8);
	board_offset   = (header.offset.board   * 8);
	product_offset = (header.offset.product * 8);

	/* Retrieve length of all modifiable components */
	chassis_len    =  *(fru_data_old + chassis_offset + 1) * 8;
	board_len      =  *(fru_data_old + board_offset   + 1) * 8;
	product_len    =  *(fru_data_old + product_offset + 1) * 8;
	product_len_new = product_len;

	/* Chassis type field */
	if (f_type == 'c' )
	{
		header_offset    = chassis_offset;
		fru_field_offset = chassis_offset + 3;
		fru_section_len  = chassis_len;
	}
	/* Board type field */
	else if (f_type == 'b' )
	{
		header_offset    = board_offset;
		fru_field_offset = board_offset + 6;
		fru_section_len  = board_len;
	}
	/* Product type field */
	else if (f_type == 'p' )
	{
		header_offset    = product_offset;
		fru_field_offset = product_offset + 3;
		fru_section_len  = product_len;
	}
	else
	{
		printf("Wrong field type.");
		rc = -1;
		goto ipmi_fru_set_field_string_rebuild_out;
	}

	/*************************
	3) Seek to field index */
	for (i = 0;i <= f_index; i++) {
		fru_field_offset_tmp = fru_field_offset;
		free_n(&fru_area);
		fru_area = (uint8_t *) get_fru_area_str(fru_data_old, &fru_field_offset);
	}

	if (!FRU_FIELD_VALID(fru_area)) {
		printf("Field not found (1)!\n");
		rc = -1;
		goto ipmi_fru_set_field_string_rebuild_out;
	}

	#ifdef DBG_RESIZE_FRU
	printf("Section Length: %u\n", fru_section_len);
	#endif

	/*************************
	4) Check number of padding bytes and bytes changed */
	for(counter = 2; counter < fru_section_len; counter ++)
	{
		if(*(fru_data_old + (header_offset + fru_section_len - counter)) == 0)
			padding_len ++;
		else
			break;
	}
	num_byte_change = strlen(f_string) - strlen(fru_area);

	#ifdef DBG_RESIZE_FRU
	printf("Padding Length: %u\n", padding_len);
	printf("NumByte Change: %i\n", num_byte_change);
	printf("Start SecChnge: %x\n", *(fru_data_old + fru_field_offset_tmp));
	printf("End SecChnge  : %x\n", *(fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1));

	printf("Start Section : %x\n", *(fru_data_old + header_offset));
	printf("End Sec wo Pad: %x\n", *(fru_data_old + header_offset + fru_section_len - 2 - padding_len));
	printf("End Section   : %x\n", *(fru_data_old + header_offset + fru_section_len - 1));
	#endif

	/* Calculate New Padding Length */
	padding_len -= num_byte_change;

	#ifdef DBG_RESIZE_FRU
	printf("New Padding Length: %i\n", padding_len);
	#endif

	/*************************
	5) Check if section must be resize.  This occur when padding length is not between 0 and 7 */
	if( (padding_len < 0) || (padding_len >= 8))
	{
		uint32_t remaining_offset = ((header.offset.product * 8) + product_len);
		int change_size_by_8;

		if(padding_len >= 8)
		{
			/* Section must be set smaller */
			change_size_by_8 = ((padding_len) / 8) * (-1);
		}
		else
		{
			/* Section must be set bigger */
			change_size_by_8 = 1 + (((padding_len+1) / 8) * (-1));
		}

		/* Recalculate padding and section length base on the section changes */
		fru_section_len += (change_size_by_8 * 8);
		padding_len     += (change_size_by_8 * 8);

		#ifdef DBG_RESIZE_FRU
		printf("change_size_by_8: %i\n", change_size_by_8);
		printf("New Padding Length: %i\n", padding_len);
		printf("change_size_by_8: %i\n", change_size_by_8);
		printf("header.offset.board: %i\n", header.offset.board);
		#endif

		/* Must move sections */
		/* Section that can be modified are as follow
			Chassis
			Board
			product */

		/* Chassis type field */
		if (f_type == 'c' )
		{
			printf("Moving Section Chassis, from %i to %i\n",
						((header.offset.board) * 8),
						((header.offset.board + change_size_by_8) * 8)
					);
			memcpy(
						(fru_data_new + ((header.offset.board + change_size_by_8) * 8)),
						(fru_data_old + (header.offset.board) * 8),
						board_len
					);
			header.offset.board   += change_size_by_8;
		}
		/* Board type field */
		if ((f_type == 'c' ) || (f_type == 'b' ))
		{
			printf("Moving Section Product, from %i to %i\n",
						((header.offset.product) * 8),
						((header.offset.product + change_size_by_8) * 8)
					);
			memcpy(
						(fru_data_new + ((header.offset.product + change_size_by_8) * 8)),
						(fru_data_old + (header.offset.product) * 8),
						product_len
					);
			header.offset.product += change_size_by_8;
		}

		if ((f_type == 'c' ) || (f_type == 'b' ) || (f_type == 'p' )) {
			printf("Change multi offset from %d to %d\n", header.offset.multi, header.offset.multi + change_size_by_8);
			header.offset.multi += change_size_by_8;
		}

		/* Adjust length of the section */
		if (f_type == 'c')
		{
			*(fru_data_new + chassis_offset + 1) += change_size_by_8;
		}
		else if( f_type == 'b')
		{
			*(fru_data_new + board_offset + 1)   += change_size_by_8;
		}
		else if( f_type == 'p')
		{
			*(fru_data_new + product_offset + 1) += change_size_by_8;
			product_len_new = *(fru_data_new + product_offset + 1) * 8;
		}

		/* Rebuild Header checksum */
		{
			unsigned char * pfru_header = (unsigned char *) &header;
			header.checksum = 0;
			for(counter = 0; counter < (sizeof(struct fru_header) -1); counter ++)
			{
				header.checksum += pfru_header[counter];
			}
			header.checksum = (0 - header.checksum);
			memcpy(fru_data_new, pfru_header, sizeof(struct fru_header));
		}

		/* Move remaining sections in 1 copy */
		printf("Moving Remaining Bytes (Multi-Rec , etc..), from %i to %i\n",
					remaining_offset,
					((header.offset.product) * 8) + product_len_new
				);
		if(((header.offset.product * 8) + product_len_new - remaining_offset) < 0)
		{
			memcpy(
						fru_data_new + (header.offset.product * 8) + product_len_new,
						fru_data_old + remaining_offset,
						fru.size - remaining_offset
					);
		}
		else
		{
			memcpy(
						fru_data_new + (header.offset.product * 8) + product_len_new,
						fru_data_old + remaining_offset,
						fru.size - ((header.offset.product * 8) + product_len_new)
					);
		}
	}

	/* Update only if it's fits padding length as defined in the spec, otherwise, it's an internal
	error */
	/*************************
	6) Update Field and sections */
	if( (padding_len >=0) && (padding_len < 8))
	{
		/* Do not requires any change in other section */

		/* Change field length */
		printf(
			"Updating Field : '%s' with '%s' ... (Length from '%d' to '%d')\n",
			fru_area, f_string, 
			(int)*(fru_data_old + fru_field_offset_tmp), 
			(int)(0xc0 + strlen(f_string)));
		*(fru_data_new + fru_field_offset_tmp) = (0xc0 + strlen(f_string));
		memcpy(fru_data_new + fru_field_offset_tmp + 1, f_string, strlen(f_string));

		/* Copy remaining bytes in section */
#ifdef DBG_RESIZE_FRU
		printf("Copying remaining of sections: %d \n",
		 (int)((fru_data_old + header_offset + fru_section_len - 1) -
		 (fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1)));
#endif

		memcpy((fru_data_new + fru_field_offset_tmp + 1 + 
			strlen(f_string)),
			(fru_data_old + fru_field_offset_tmp + 1 + 
			strlen(fru_area)),
		((fru_data_old + header_offset + fru_section_len - 1) -
		(fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1)));

		/* Add Padding if required */
		for(counter = 0; counter < padding_len; counter ++)
		{
			*(fru_data_new + header_offset + fru_section_len - 1 - 
			  padding_len + counter) = 0;
		}

		/* Calculate New Checksum */
		cksum = 0;
		for( counter = 0; counter <fru_section_len-1; counter ++ )
		{
			cksum += *(fru_data_new + header_offset + counter);
		}
		*(fru_data_new + header_offset + fru_section_len - 1) = (0 - cksum);

		#ifdef DBG_RESIZE_FRU
		printf("Calculate New Checksum: %x\n", (0 - cksum));
		#endif
	}
	else
	{
		printf( "Internal error, padding length %i (must be from 0 to 7) ", padding_len );
		rc = -1;
		goto ipmi_fru_set_field_string_rebuild_out;
	}

	/*************************
	7) Finally, write new FRU */
	printf("Writing new FRU.\n");
	if( write_fru_area( intf, &fru, fruId, 0, 0, fru.size, fru_data_new ) < 0 )
	{
		printf("Write to FRU data failed.\n");
		rc = -1;
		goto ipmi_fru_set_field_string_rebuild_out;
	}

	printf("Done.\n");

ipmi_fru_set_field_string_rebuild_out:
	free_n(&fru_area);
	free_n(&fru_data_new);
	free_n(&fru_data_old);

	return rc;
}