text:
#include <stdlib.h>
#include <string.h>
#include "mmc.h"
#include "partition_parser.h"
#define GPT_HEADER_SIZE 92
#define GPT_LBA 1
#define PARTITION_ENTRY_SIZE 128
static bool flashing_gpt = 0;
static bool parse_secondary_gpt = 0;
__WEAK void mmc_set_lun(uint8_t lun)
{
}

__WEAK uint8_t mmc_get_lun(void)
{
	return 0;
}

__WEAK void mmc_read_partition_table(uint8_t arg)
{
	if(partition_read_table())
	{
		dprintf(CRITICAL, "Error reading the partition table info\n");
		ASSERT(0);
	}
}

static uint32_t mmc_boot_read_gpt(uint32_t block_size);
static uint32_t mmc_boot_read_mbr(uint32_t block_size);
static void mbr_fill_name(struct partition_entry *partition_ent,
						  uint32_t type);
static uint32_t partition_verify_mbr_signature(uint32_t size,
											   uint8_t *buffer);
static uint32_t mbr_partition_get_type(uint32_t size, uint8_t *partition,
									   uint32_t *partition_type);

static uint32_t partition_get_type(uint32_t size, uint8_t *partition,
								   uint32_t *partition_type);
static uint32_t partition_parse_gpt_header(uint8_t *buffer,
										   uint64_t *first_usable_lba,
										   uint32_t *partition_entry_size,
										   uint32_t *header_size,
										   uint32_t *max_partition_count);

static uint32_t write_mbr(uint32_t, uint8_t *mbrImage, uint32_t block_size);
static uint32_t write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size);

//[LGE_UPDATE_S] DMS_SYSTEM dms-fota@lge.com 2014/10/06
static uint32_t mmc_boot_read_gpt_crc(uint32_t block_size);
//[LGE_UPDATE_E] DMS_SYSTEM dms-fota@lge.com 2014/10/06

char *ext3_partitions[] =
    { "system", "userdata", "persist", "cache", "tombstones" };
char *vfat_partitions[] = { "modem", "mdm", "NONE" };

unsigned int ext3_count = 0;
unsigned int vfat_count = 0;

struct partition_entry *partition_entries;
static unsigned gpt_partitions_exist = 0;
static unsigned partition_count;

//[LGE_UPDATE_S] DMS_SYSTEM dms-fota@lge.com 2014/10/06
unsigned int get_gpt_crc_header()
{
    unsigned int ret;
    uint32_t block_size;

    block_size = mmc_get_device_blocksize();

    dprintf(INFO, "get_gpt_crc_header gpt\n");
    /* Read GPT of the card if exist */
    ret = mmc_boot_read_gpt_crc(block_size);

    return ret;
}

/*
 * Read GPT CRC from MMC
 */
static unsigned int mmc_boot_read_gpt_crc(uint32_t block_size)
{
    int ret = 0;
    unsigned int header_crc = 0;
    uint8_t *data = NULL;

    /* Get the density of the mmc device */

    data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
    if (!data)
    {
        dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
        ret = -1;
        goto end;
    }

    /* Print out the GPT first */
    ret = mmc_read(block_size, (unsigned int *)data, block_size);
    if (ret)
    {
        dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
        goto end;
    }

    /* Check GPT Signature */
    if (((uint32_t *) data)[0] != GPT_SIGNATURE_2 ||
        ((uint32_t *) data)[1] != GPT_SIGNATURE_1)
    {
        goto end;
    }

    dprintf(INFO, "GPT: header_crc (before) = %X\n", header_crc);
    header_crc = GET_LWORD_FROM_BYTE(data + HEADER_CRC_OFFSET);
    dprintf(INFO, "GPT: header_crc (after) = %X\n", header_crc);

end:
    if (data)
        free(data);

    if ( header_crc == 0 )
    {
        return 0;
    }
    else
    {
        return 1;
    }
}
//[LGE_UPDATE_E] DMS_SYSTEM dms-fota@lge.com 2014/10/06

unsigned int partition_read_table()
{
	unsigned int ret;
	uint32_t block_size;

	block_size = mmc_get_device_blocksize();

	/* Allocate partition entries array */
	if(!partition_entries)
	{
		partition_entries = (struct partition_entry *) calloc(NUM_PARTITIONS, sizeof(struct partition_entry));
		ASSERT(partition_entries);
	}

	/* Read MBR of the card */
	ret = mmc_boot_read_mbr(block_size);
	if (ret) {
		dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
		return 1;
	}

	/* Read GPT of the card if exist */
	if (gpt_partitions_exist) {
		ret = mmc_boot_read_gpt(block_size);
		if (ret) {
			dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
			return 1;
		}
	}
	return 0;
}

/*
 * Read MBR from MMC card and fill partition table.
 */
static unsigned int mmc_boot_read_mbr(uint32_t block_size)
{
	uint8_t *buffer = NULL;
	unsigned int dtype;
	unsigned int dfirstsec;
	unsigned int EBR_first_sec;
	unsigned int EBR_current_sec;
	int ret = 0;
	int idx, i;

#ifdef WITH_LGE_COMMON
    int j;
    uint32_t mmc_status, mmc_ret = 0;
    struct mmc_device *dev;
    dev = target_mmc_device();
    for (j = 0 ; j < 5 ; j++){
        mmc_ret = mmc_get_card_status(&dev->host, &dev->card, &mmc_status);
        if (mmc_ret) {
            DBG(CRITICAL, "Get card status failed \n");
        }
    }
#endif

	buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));

	if (!buffer)
	{
		dprintf(CRITICAL, "Error allocating memory while reading partition table\n");
		ret = -1;
		goto end;
	}

	/* Print out the MBR first */
	ret = mmc_read(0, (unsigned int *)buffer, block_size);
	if (ret) {
		dprintf(CRITICAL, "Could not read partition from mmc\n");
		goto end;
	}

	/* Check to see if signature exists */
	ret = partition_verify_mbr_signature(block_size, buffer);
	if (ret) {
		goto end;
	}

	/*
	 * Process each of the four partitions in the MBR by reading the table
	 * information into our mbr table.
	 */
	idx = TABLE_ENTRY_0;
	for (i = 0; i < 4; i++) {
		/* Type 0xEE indicates end of MBR and GPT partitions exist */
		dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
		if (dtype == MBR_PROTECTED_TYPE) {
			gpt_partitions_exist = 1;
			goto end;
		}
		partition_entries[partition_count].dtype = dtype;
		partition_entries[partition_count].attribute_flag =
		    buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
		partition_entries[partition_count].first_lba =
		    GET_LWORD_FROM_BYTE(&buffer[idx +
						i * TABLE_ENTRY_SIZE +
						OFFSET_FIRST_SEC]);
		partition_entries[partition_count].size =
		    GET_LWORD_FROM_BYTE(&buffer[idx +
						i * TABLE_ENTRY_SIZE +
						OFFSET_SIZE]);
		dfirstsec = partition_entries[partition_count].first_lba;
		mbr_fill_name(&partition_entries[partition_count],
			      partition_entries[partition_count].dtype);
		partition_count++;
		if (partition_count == NUM_PARTITIONS)
			goto end;
	}

	/* See if the last partition is EBR, if not, parsing is done */
	if (dtype != MBR_EBR_TYPE) {
		goto end;
	}

	EBR_first_sec = dfirstsec;
	EBR_current_sec = dfirstsec;

	ret = mmc_read((EBR_first_sec * block_size), (unsigned int *)buffer, block_size);
	if (ret)
		goto end;

	/* Loop to parse the EBR */
	for (i = 0;; i++) {
		ret = partition_verify_mbr_signature(block_size, buffer);
		if (ret) {
			ret = 0;
			break;
		}
		partition_entries[partition_count].attribute_flag =
		    buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
		partition_entries[partition_count].dtype =
		    buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
		partition_entries[partition_count].first_lba =
		    GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
						OFFSET_FIRST_SEC]) +
		    EBR_current_sec;
		partition_entries[partition_count].size =
		    GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
		mbr_fill_name(&(partition_entries[partition_count]),
			      partition_entries[partition_count].dtype);
		partition_count++;
		if (partition_count == NUM_PARTITIONS)
			goto end;

		dfirstsec =
		    GET_LWORD_FROM_BYTE(&buffer
					[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
		if (dfirstsec == 0) {
			/* Getting to the end of the EBR tables */
			break;
		}
		/* More EBR to follow - read in the next EBR sector */
		dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
			+ dfirstsec);
		ret = mmc_read(((EBR_first_sec + dfirstsec) * block_size),(unsigned int *)buffer,
						block_size);
		if (ret)
			goto end;

		EBR_current_sec = EBR_first_sec + dfirstsec;
	}
end:
	if (buffer)
		free(buffer);

	return ret;
}

/*
 * Read GPT from MMC and fill partition table
 */
static unsigned int mmc_boot_read_gpt(uint32_t block_size)
{
	int ret = 0;
	unsigned int header_size;
	unsigned long long first_usable_lba;
	unsigned long long backup_header_lba;
	unsigned long long card_size_sec;
	unsigned int max_partition_count = 0;
	unsigned int partition_entry_size;
	unsigned int i = 0;	/* Counter for each block */
	unsigned int j = 0;	/* Counter for each entry in a block */
	unsigned int n = 0;	/* Counter for UTF-16 -> 8 conversion */
	unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
	/* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
	unsigned long long partition_0;
	uint64_t device_density;
	uint8_t *data = NULL;
	uint32_t part_entry_cnt = block_size / ENTRY_SIZE;

	/* Get the density of the mmc device */

	device_density = mmc_get_device_capacity();

	data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
	if (!data)
	{
		dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
		ret = -1;
		goto end;
	}

	/* Print out the GPT first */
	ret = mmc_read(block_size, (unsigned int *)data, block_size);
	if (ret)
	{
		dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
		goto end;
	}
	ret = partition_parse_gpt_header(data, &first_usable_lba,
					 &partition_entry_size, &header_size,
					 &max_partition_count);
	if (ret) {
		dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");

		/* Check the backup gpt */

		/* Get size of MMC */
		card_size_sec = (device_density) / block_size;
		ASSERT (card_size_sec > 0);

		backup_header_lba = card_size_sec - 1;
		ret = mmc_read((backup_header_lba * block_size), (unsigned int *)data,
						block_size);

		if (ret) {
			dprintf(CRITICAL,
				"GPT: Could not read backup gpt from mmc\n");
			goto end;
		}

		parse_secondary_gpt = 1; //[[ [LGE_UPDATE_E] DMS_SYSTEM 2015/7/11
		ret = partition_parse_gpt_header(data, &first_usable_lba,
						 &partition_entry_size,
						 &header_size,
						 &max_partition_count);

		parse_secondary_gpt = 0;//[[ [LGE_UPDATE_E] DMS_SYSTEM 2015/7/11

		if (ret) {
			dprintf(CRITICAL,
				"GPT: Primary and backup signatures invalid\n");
			goto end;
		}
	}
	partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
	/* Read GPT Entries */

#ifdef LGE_WITH_FLEXIBLE_GPT
	partition_count = 0;
#endif
	for (i = 0; i < (ROUNDUP(max_partition_count, part_entry_cnt)) / part_entry_cnt; i++) {
		ASSERT(partition_count < NUM_PARTITIONS);
		ret = mmc_read((partition_0 * block_size) + (i * block_size),
						(uint32_t *) data, block_size);

		if (ret) {
			dprintf(CRITICAL,
				"GPT: mmc read card failed reading partition entries.\n");
			goto end;
		}

		for (j = 0; j < part_entry_cnt; j++) {
			memcpy(&(partition_entries[partition_count].type_guid),
			       &data[(j * partition_entry_size)],
			       PARTITION_TYPE_GUID_SIZE);
			if (partition_entries[partition_count].type_guid[0] ==
			    0x00
			    && partition_entries[partition_count].
			    type_guid[1] == 0x00) {
				i = ROUNDUP(max_partition_count, part_entry_cnt);
				break;
			}
			memcpy(&
			       (partition_entries[partition_count].
				unique_partition_guid),
			       &data[(j * partition_entry_size) +
				     UNIQUE_GUID_OFFSET],
			       UNIQUE_PARTITION_GUID_SIZE);
			partition_entries[partition_count].first_lba =
			    GET_LLWORD_FROM_BYTE(&data
						 [(j * partition_entry_size) +
						  FIRST_LBA_OFFSET]);
			partition_entries[partition_count].last_lba =
			    GET_LLWORD_FROM_BYTE(&data
						 [(j * partition_entry_size) +
						  LAST_LBA_OFFSET]);
			partition_entries[partition_count].size =
			    partition_entries[partition_count].last_lba -
			    partition_entries[partition_count].first_lba + 1;
			partition_entries[partition_count].attribute_flag =
			    GET_LLWORD_FROM_BYTE(&data
						 [(j * partition_entry_size) +
						  ATTRIBUTE_FLAG_OFFSET]);

			memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
			memcpy(UTF16_name, &data[(j * partition_entry_size) +
						 PARTITION_NAME_OFFSET],
			       MAX_GPT_NAME_SIZE);
			partition_entries[partition_count].lun = mmc_get_lun();

			/*
			 * Currently partition names in *.xml are UTF-8 and lowercase
			 * Only supporting english for now so removing 2nd byte of UTF-16
			 */
			for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
				partition_entries[partition_count].name[n] =
				    UTF16_name[n * 2];
			}
			partition_count++;
		}
	}
end:
	if (data)
		free(data);

	return ret;
}

static unsigned int write_mbr_in_blocks(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
{
	unsigned int dtype;
	unsigned int dfirstsec;
	unsigned int ebrSectorOffset;
	unsigned char *ebrImage;
	unsigned char *lastAddress;
	int idx, i;
	unsigned int ret;

	/* Write the first block */
	ret = mmc_write(0, block_size, (unsigned int *)mbrImage);
	if (ret) {
		dprintf(CRITICAL, "Failed to write mbr partition\n");
		goto end;
	}
	dprintf(SPEW, "write of first MBR block ok\n");
	/*
	   Loop through the MBR table to see if there is an EBR.
	   If found, then figure out where to write the first EBR
	 */
	idx = TABLE_ENTRY_0;
	for (i = 0; i < 4; i++) {
		dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
		if (MBR_EBR_TYPE == dtype) {
			dprintf(SPEW, "EBR found.\n");
			break;
		}
	}
	if (MBR_EBR_TYPE != dtype) {
		dprintf(SPEW, "No EBR in this image\n");
		goto end;
	}
	/* EBR exists.  Write each EBR block to mmc */
	ebrImage = mbrImage + block_size;
	ebrSectorOffset =
	    GET_LWORD_FROM_BYTE(&mbrImage
				[idx + i * TABLE_ENTRY_SIZE +
				 OFFSET_FIRST_SEC]);
	dfirstsec = 0;
	dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
	lastAddress = mbrImage + size;
	while (ebrImage < lastAddress) {
		dprintf(SPEW, "writing to 0x%X\n",
			(ebrSectorOffset + dfirstsec) * block_size);
		ret =
		    mmc_write((ebrSectorOffset + dfirstsec) * block_size,
			      block_size, (unsigned int *)ebrImage);
		if (ret) {
			dprintf(CRITICAL,
				"Failed to write EBR block to sector 0x%X\n",
				dfirstsec);
			goto end;
		}
		dfirstsec =
		    GET_LWORD_FROM_BYTE(&ebrImage
					[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
		ebrImage += block_size;
	}
	dprintf(INFO, "MBR written to mmc successfully\n");
 end:
	return ret;
}

/* Write the MBR/EBR to the MMC. */
static unsigned int write_mbr(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
{
	unsigned int ret;

	/* Verify that passed in block is a valid MBR */
	ret = partition_verify_mbr_signature(size, mbrImage);
	if (ret) {
		goto end;
	}

	/* Write the MBR/EBR to mmc */
	ret = write_mbr_in_blocks(size, mbrImage, block_size);
	if (ret) {
		dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
		goto end;
	}
	/* Re-read the MBR partition into mbr table */
	ret = mmc_boot_read_mbr(block_size);
	if (ret) {
		dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
		goto end;
	}
	partition_dump();
 end:
	return ret;
}

/*
 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
*/
int reflect(int data, int len)
{
	int ref = 0;

	for (int i = 0; i < len; i++) {
		if (data & 0x1) {
			ref |= (1 << ((len - 1) - i));
		}
		data = (data >> 1);
	}

	return ref;
}

/*
* Function to calculate the CRC32
*/
unsigned int calculate_crc32(unsigned char *buffer, int len)
{
	int byte_length = 8;	/*length of unit (i.e. byte) */
	int msb = 0;
	int polynomial = 0x04C11DB7;	/* IEEE 32bit polynomial */
	unsigned int regs = 0xFFFFFFFF;	/* init to all ones */
	int regs_mask = 0xFFFFFFFF;	/* ensure only 32 bit answer */
	int regs_msb = 0;
	unsigned int reflected_regs;

	for (int i = 0; i < len; i++) {
		int data_byte = buffer[i];
		data_byte = reflect(data_byte, 8);
		for (int j = 0; j < byte_length; j++) {
			msb = data_byte >> (byte_length - 1);	/* get MSB */
			msb &= 1;	/* ensure just 1 bit */
			regs_msb = (regs >> 31) & 1;	/* MSB of regs */
			regs = regs << 1;	/* shift regs for CRC-CCITT */
			if (regs_msb ^ msb) {	/* MSB is a 1 */
				regs = regs ^ polynomial;	/* XOR with generator poly */
			}
			regs = regs & regs_mask;	/* Mask off excess upper bits */
			data_byte <<= 1;	/* get to next bit */
		}
	}
	regs = regs & regs_mask;
	reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;

	return reflected_regs;
}

/*
 * Write the GPT Partition Entry Array to the MMC.
 */
static unsigned int
write_gpt_partition_array(uint8_t *header,
						  uint32_t partition_array_start,
						  uint32_t array_size,
						  uint32_t block_size)
{
	unsigned int ret = 1;
	unsigned long long partition_entry_lba;
	unsigned long long partition_entry_array_start_location;

	partition_entry_lba =
	    GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
	partition_entry_array_start_location = partition_entry_lba * block_size;

	ret = mmc_write(partition_entry_array_start_location, array_size,
			(unsigned int *)partition_array_start);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: FAILED to write the partition entry array\n");
		goto end;
	}

 end:
	return ret;
}

static void
patch_gpt(uint8_t *gptImage, uint64_t density, uint32_t array_size,
		  uint32_t max_part_count, uint32_t part_entry_size, uint32_t block_size)
{
	unsigned int partition_entry_array_start;
	unsigned char *primary_gpt_header;
	unsigned char *secondary_gpt_header;
	unsigned int offset;
	unsigned long long card_size_sec;
	int total_part = 0;
	unsigned int last_part_offset;
	unsigned int crc_value;

	/* Get size of MMC */
	card_size_sec = (density) / block_size;
	/* Working around cap at 4GB */
	if (card_size_sec == 0) {
		card_size_sec = 4 * 1024 * 1024 * 2 - 1;
	}

	/* Patching primary header */
	primary_gpt_header = (gptImage + block_size);
	PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
		      ((long long)(card_size_sec - 1)));
	PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
		      ((long long)(card_size_sec - 34)));

	/* Patching backup GPT */
	offset = (2 * array_size);
	secondary_gpt_header = offset + block_size + primary_gpt_header;
	PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
		      ((long long)(card_size_sec - 1)));
	PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
		      ((long long)(card_size_sec - 34)));
	PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
		      ((long long)(card_size_sec - 33)));

	/* Find last partition */
	while (*(primary_gpt_header + block_size + total_part * ENTRY_SIZE) !=
	       0) {
		total_part++;
	}

	/* Patching last partition */
	last_part_offset =
	    (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
	PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset,
		      (long long)(card_size_sec - 34));
	PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset +
		      array_size, (long long)(card_size_sec - 34));

	/* Updating CRC of the Partition entry array in both headers */
	partition_entry_array_start = (unsigned int)primary_gpt_header + block_size;
	crc_value = calculate_crc32((unsigned char *)partition_entry_array_start,
				    max_part_count * part_entry_size);
	PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);

	crc_value = calculate_crc32((unsigned char *)partition_entry_array_start + array_size,
				    max_part_count * part_entry_size);
	PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);

	/* Clearing CRC fields to calculate */
	PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
	crc_value = calculate_crc32(primary_gpt_header, 92);
	PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);

	PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
	crc_value = (calculate_crc32(secondary_gpt_header, 92));
	PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);

}

/*
 * Write the GPT to the MMC.
 */
static unsigned int write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size)
{
	unsigned int ret = 1;
	unsigned int header_size;
	unsigned long long first_usable_lba;
	unsigned long long backup_header_lba;
	unsigned int max_partition_count = 0;
	unsigned int partition_entry_size;
	unsigned int partition_entry_array_start;
	unsigned char *primary_gpt_header;
	unsigned char *secondary_gpt_header;
	unsigned int offset;
	unsigned int partition_entry_array_size;
	unsigned long long primary_header_location;	/* address on the emmc card */
	unsigned long long secondary_header_location;	/* address on the emmc card */
	uint64_t device_density;

	/* Verify that passed block has a valid GPT primary header */
	primary_gpt_header = (gptImage + block_size);
	ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
					 &partition_entry_size, &header_size,
					 &max_partition_count);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Primary signature invalid cannot write GPT\n");
		goto end;
	}

	/* Get the density of the mmc device */

	device_density = mmc_get_device_capacity();

	/* Verify that passed block has a valid backup GPT HEADER */
	partition_entry_array_size = partition_entry_size * max_partition_count;
	if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
		partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
	}
	offset = (2 * partition_entry_array_size);
	secondary_gpt_header = offset + block_size + primary_gpt_header;
	parse_secondary_gpt = 1;
	ret =
	    partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
				       &partition_entry_size, &header_size,
				       &max_partition_count);
	parse_secondary_gpt = 0;
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Backup signature invalid cannot write GPT\n");
		goto end;
	}

	/* Patching the primary and the backup header of the GPT table */
	patch_gpt(gptImage, device_density, partition_entry_array_size,
		  max_partition_count, partition_entry_size, block_size);

	/* Erasing the eMMC card before writing */
	ret = mmc_erase_card(0x00000000, device_density);
	if (ret) {
		dprintf(CRITICAL, "Failed to erase the eMMC card\n");
		goto end;
	}

	/* Writing protective MBR */
	ret = mmc_write(0, block_size, (unsigned int *)gptImage);
	if (ret) {
		dprintf(CRITICAL, "Failed to write Protective MBR\n");
		goto end;
	}
	/* Writing the primary GPT header */
	primary_header_location = block_size;
	ret = mmc_write(primary_header_location, block_size,
			(unsigned int *)primary_gpt_header);
	if (ret) {
		dprintf(CRITICAL, "Failed to write GPT header\n");
		goto end;
	}

	/* Writing the backup GPT header */
	backup_header_lba = GET_LLWORD_FROM_BYTE
	    (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
	secondary_header_location = backup_header_lba * block_size;
	ret = mmc_write(secondary_header_location, block_size,
			(unsigned int *)secondary_gpt_header);
	if (ret) {
		dprintf(CRITICAL, "Failed to write GPT backup header\n");
		goto end;
	}

	/* Writing the partition entries array for the primary header */
	partition_entry_array_start = (unsigned int)primary_gpt_header + block_size;
	ret = write_gpt_partition_array(primary_gpt_header,
					partition_entry_array_start,
					partition_entry_array_size, block_size);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Could not write GPT Partition entries array\n");
		goto end;
	}

	/*Writing the partition entries array for the backup header */
	partition_entry_array_start = (unsigned int)primary_gpt_header + block_size +
	    partition_entry_array_size;
	ret = write_gpt_partition_array(secondary_gpt_header,
					partition_entry_array_start,
					partition_entry_array_size, block_size);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Could not write GPT Partition entries array\n");
		goto end;
	}

	/* Re-read the GPT partition table */
	dprintf(INFO, "Re-reading the GPT Partition Table\n");
	partition_count = 0;
	flashing_gpt = 0;
	mmc_read_partition_table(0);
	partition_dump();
	dprintf(CRITICAL, "GPT: Partition Table written\n");
	memset(primary_gpt_header, 0x00, size);

 end:
	return ret;
}

unsigned int write_partition(unsigned size, unsigned char *partition)
{
	unsigned int ret = 1;
	unsigned int partition_type;
	uint32_t block_size;

	if (partition == 0) {
		dprintf(CRITICAL, "NULL partition\n");
		goto end;
	}

	block_size = mmc_get_device_blocksize();
	ret = partition_get_type(size, partition, &partition_type);
	if (ret)
		goto end;

	switch (partition_type) {
	case PARTITION_TYPE_MBR:
		dprintf(INFO, "Writing MBR partition\n");
		ret = write_mbr(size, partition, block_size);
		break;

	case PARTITION_TYPE_GPT:
		dprintf(INFO, "Writing GPT partition\n");
		flashing_gpt = 1;
		ret = write_gpt(size, partition, block_size);
		dprintf(CRITICAL, "Re-Flash all the partitions\n");
		break;

	default:
		dprintf(CRITICAL, "Invalid partition\n");
		ret = 1;
		goto end;
	}

 end:
	return ret;
}

/*
 * Fill name for android partition found.
 */
static void
mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
{
	switch (type) {
		memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
	case MBR_MODEM_TYPE:
	case MBR_MODEM_TYPE2:
		/* if already assigned last name available then return */
		if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
			return;
		strlcpy((char *)partition_ent->name,
			(const char *)vfat_partitions[vfat_count],
			sizeof(partition_ent->name));
		vfat_count++;
		break;
	case MBR_SBL1_TYPE:
		memcpy(partition_ent->name, "sbl1", 4);
		break;
	case MBR_SBL2_TYPE:
		memcpy(partition_ent->name, "sbl2", 4);
		break;
	case MBR_SBL3_TYPE:
		memcpy(partition_ent->name, "sbl3", 4);
		break;
	case MBR_RPM_TYPE:
		memcpy(partition_ent->name, "rpm", 3);
		break;
	case MBR_TZ_TYPE:
		memcpy(partition_ent->name, "tz", 2);
		break;
	case MBR_ABOOT_TYPE:
#if PLATFORM_MSM7X27A
		memcpy(partition_ent->name, "FOTA", 4);
#else
		memcpy(partition_ent->name, "aboot", 5);
#endif
		break;
	case MBR_BOOT_TYPE:
		memcpy(partition_ent->name, "boot", 4);
		break;
	case MBR_MODEM_ST1_TYPE:
		memcpy(partition_ent->name, "modem_st1", 9);
		break;
	case MBR_MODEM_ST2_TYPE:
		memcpy(partition_ent->name, "modem_st2", 9);
		break;
	case MBR_EFS2_TYPE:
		memcpy(partition_ent->name, "efs2", 4);
		break;
	case MBR_USERDATA_TYPE:
		if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
			return;
		strlcpy((char *)partition_ent->name,
			(const char *)ext3_partitions[ext3_count],
			sizeof(partition_ent->name));
		ext3_count++;
		break;
	case MBR_RECOVERY_TYPE:
		memcpy(partition_ent->name, "recovery", 8);
		break;
	case MBR_MISC_TYPE:
		memcpy(partition_ent->name, "misc", 4);
		break;
	case MBR_SSD_TYPE:
		memcpy(partition_ent->name, "ssd", 3);
		break;
	};
}

/*
 * Find index of parition in array of partition entries
 */
int partition_get_index(const char *name)
{
	unsigned int input_string_length = strlen(name);
	unsigned n;

	if( partition_count >= NUM_PARTITIONS)
	{
		return INVALID_PTN;
	}
	for (n = 0; n < partition_count; n++) {
		if ((input_string_length == strlen((const char *)&partition_entries[n].name))
			&& !memcmp(name, &partition_entries[n].name, input_string_length)) {
			return n;
		}
	}
	return INVALID_PTN;
}

/* Get size of the partition */
unsigned long long partition_get_size(int index)
{
	uint32_t block_size;

	block_size = mmc_get_device_blocksize();

	if (index == INVALID_PTN)
		return 0;
	else {
		return partition_entries[index].size * block_size;
	}
}

/* Get offset of the partition */
unsigned long long partition_get_offset(int index)
{
	uint32_t block_size;

	block_size = mmc_get_device_blocksize();

	if (index == INVALID_PTN)
		return 0;
	else {
		return partition_entries[index].first_lba * block_size;
	}
}

struct partition_info partition_get_info(const char *name)
{
	struct partition_info info = {0};

	int index = INVALID_PTN;

	if(!name)
	{
		dprintf(CRITICAL, "Invalid partition name passed\n");
		goto out;
	}

	index = partition_get_index(name);

	if (index != INVALID_PTN)
	{
		info.offset = partition_get_offset(index);
		info.size   = partition_get_size(index);
	}
	else
	{
		dprintf(CRITICAL, "Error unable to find partition : [%s]\n", name);
	}
out:
	return info;
}

uint8_t partition_get_lun(int index)
{
	return partition_entries[index].lun;
}

/* Debug: Print all parsed partitions */
void partition_dump()
{
	unsigned i = 0;
	for (i = 0; i < partition_count; i++) {
		dprintf(SPEW,
			"ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
			i, partition_entries[i].name, partition_entries[i].size,
			partition_entries[i].dtype,
			partition_entries[i].first_lba,
			partition_entries[i].last_lba);
	}
}

static unsigned int
partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
{
	/* Avoid checking past end of buffer */
	if ((TABLE_SIGNATURE + 1) > size) {
		return 1;
	}
	/* Check to see if signature exists */
	if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
	    (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
		dprintf(CRITICAL, "MBR signature does not match.\n");
		return 1;
	}
	return 0;
}

static unsigned int
mbr_partition_get_type(unsigned size, unsigned char *partition,
		       unsigned int *partition_type)
{
	unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;

	if (size < (type_offset + sizeof (*partition_type))) {
		goto end;
	}

	*partition_type = partition[type_offset];
 end:
	return 0;
}

static unsigned int
partition_get_type(unsigned size, unsigned char *partition,
		   unsigned int *partition_type)
{
	unsigned int ret = 0;

	/*
	 * If the block contains the MBR signature, then it's likely either
	 * MBR or MBR with protective type (GPT).  If the MBR signature is
	 * not there, then it could be the GPT backup.
	 */

	/* First check the MBR signature */
	ret = partition_verify_mbr_signature(size, partition);
	if (!ret) {
		unsigned int mbr_partition_type = PARTITION_TYPE_MBR;

		/* MBR signature verified.  This could be MBR, MBR + EBR, or GPT */
		ret =
		    mbr_partition_get_type(size, partition,
					   &mbr_partition_type);
		if (ret) {
			dprintf(CRITICAL, "Cannot get TYPE of partition");
		} else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
			*partition_type = PARTITION_TYPE_GPT;
		} else {
			*partition_type = PARTITION_TYPE_MBR;
		}
	} else {
		/*
		 * This could be the GPT backup.  Make that assumption for now.
		 * Anybody who treats the block as GPT backup should check the
		 * signature.
		 */
		*partition_type = PARTITION_TYPE_GPT_BACKUP;
	}
	return ret;
}

/*
 * Parse the gpt header and get the required header fields
 * Return 0 on valid signature
 */
static unsigned int
partition_parse_gpt_header(unsigned char *buffer,
			   unsigned long long *first_usable_lba,
			   unsigned int *partition_entry_size,
			   unsigned int *header_size,
			   unsigned int *max_partition_count)
{
	uint32_t crc_val_org = 0;
	uint32_t crc_val = 0;
	uint32_t ret = 0;
	unsigned char *new_buffer = NULL;
	unsigned long long last_usable_lba = 0;
	unsigned long long partition_0 = 0;
	unsigned long long current_lba = 0;
	uint32_t block_size = mmc_get_device_blocksize();
	/* Get the density of the mmc device */
	uint64_t device_density = mmc_get_device_capacity();

	/* Check GPT Signature */
	if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
	    ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
		return 1;

	*header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
	/*check for header size too small*/
	if (*header_size < GPT_HEADER_SIZE) {
		dprintf(CRITICAL,"GPT Header size is too small\n");
		return 1;
	}
	/*check for header size too large*/
	if (*header_size > block_size) {
		dprintf(CRITICAL,"GPT Header size is too large\n");
		return 1;
	}

	crc_val_org = GET_LWORD_FROM_BYTE(&buffer[HEADER_CRC_OFFSET]);
	crc_val = 0;
	/*Write CRC to 0 before we calculate the crc of the GPT header*/
	PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);

	crc_val  = calculate_crc32(buffer, *header_size);
	if (crc_val != crc_val_org) {
		dprintf(CRITICAL,"Header crc mismatch crc_val = %u with crc_val_org = %u\n", crc_val,crc_val_org);
		return 1;
	}
	else
		PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);

	current_lba =
	    GET_LLWORD_FROM_BYTE(&buffer[PRIMARY_HEADER_OFFSET]);
	*first_usable_lba =
	    GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
	*max_partition_count =
	    GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
	*partition_entry_size =
	    GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
	last_usable_lba =
	    GET_LLWORD_FROM_BYTE(&buffer[LAST_USABLE_LBA_OFFSET]);

	/*current lba and GPT lba should be same*/
	if (!parse_secondary_gpt) {
		if (current_lba != GPT_LBA) {
			dprintf(CRITICAL,"GPT first usable LBA mismatch\n");
			return 1;
		}
	}
	/*check for first lba should be with in the valid range*/
	if (*first_usable_lba > (device_density/block_size)) {
		dprintf(CRITICAL,"Invalid first_usable_lba\n");
		return 1;
	}
	/*check for last lba should be with in the valid range*/
	if (last_usable_lba > (device_density/block_size)) {
		dprintf(CRITICAL,"Invalid last_usable_lba\n");
		return 1;
	}
	/*check for partition entry size*/
	if (*partition_entry_size != PARTITION_ENTRY_SIZE) {
		dprintf(CRITICAL,"Invalid parition entry size\n");
		return 1;
	}

	if ((*max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(*partition_entry_size))) {
		dprintf(CRITICAL, "Invalid maximum partition count\n");
		return 1;
	}

	new_buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP((*max_partition_count) * (*partition_entry_size), CACHE_LINE));

	if (!new_buffer)
	{
		dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
		return 1;
	}

	if (flashing_gpt) {
		if (parse_secondary_gpt) {
			memcpy(new_buffer, buffer - MIN_PARTITION_ARRAY_SIZE, (*max_partition_count) * (*partition_entry_size));
		}
		else
			memcpy(new_buffer, buffer + block_size, (*max_partition_count) * (*partition_entry_size));
	}
	else {
		partition_0 = GET_LLWORD_FROM_BYTE(&buffer[PARTITION_ENTRIES_OFFSET]);
		/*start LBA should always be 2 in primary GPT*/
		if(partition_0 != 0x2) {
			dprintf(CRITICAL, "Starting LBA mismatch\n");
			goto fail;

		}
		/*read the partition entries to new_buffer*/
		ret = mmc_read((partition_0) * (block_size), (unsigned int *)new_buffer, (*max_partition_count) * (*partition_entry_size));
		if (ret)
		{
			dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
			goto fail;
		}
	}
	crc_val_org = GET_LWORD_FROM_BYTE(&buffer[PARTITION_CRC_OFFSET]);

	crc_val  = calculate_crc32(new_buffer,((*max_partition_count) * (*partition_entry_size)));
	if (crc_val != crc_val_org) {
		dprintf(CRITICAL,"Partition entires crc mismatch crc_val= %u with crc_val_org= %u\n",crc_val,crc_val_org);
		ret = 1;
	}

fail:
	free(new_buffer);
	return ret;
}

bool partition_gpt_exists()
{
	return (gpt_partitions_exist != 0);
}

int partition_read_only(int index)
{
	 return partition_entries[index].attribute_flag >> PART_ATT_READONLY_OFFSET;
}

#ifdef LGE_WITH_FLEXIBLE_GPT

/*
 * Read the GPT from the MMC.
 */
unsigned int
read_gpt(unsigned size, unsigned char *gptImage)
{
	unsigned char *buf = gptImage;
	int ret = 0;

	/* Print out the GPT first */
	ret = mmc_read(0, (unsigned int *)buf, size);
	if (ret) {
		dprintf(CRITICAL, "Could not read partition from mmc\n");
		return ret;
	}

	/* Check to see if signature exists */
	ret = partition_verify_mbr_signature(BLOCK_SIZE, buf);
	if (ret)
		return ret;

	buf = &gptImage[PROTECTIVE_MBR_SIZE];
	/* Check GPT Signature */
	if (((uint32_t *) buf)[0] != GPT_SIGNATURE_2 ||
	    ((uint32_t *) buf)[1] != GPT_SIGNATURE_1) {
		dprintf(CRITICAL, "GPT signature does not match.\n");
		return 1;
	}
	return ret;
}

/*
 * Replace gpt entry.
 */
unsigned int
replace_gpt_entry(unsigned size, unsigned char *gptImage, const char *name,
		unsigned long long first_lba, unsigned long long last_lba)
{

	unsigned int ret = 1;
	unsigned char *data;
	unsigned long long partition_0;
	unsigned int header_size;
	unsigned long long first_usable_lba;
	unsigned int max_partition_count = 0;
	unsigned int partition_entry_size;
	unsigned char *primary_gpt_header;
	char gpt_name[MAX_GPT_NAME_SIZE] = {0, };
	unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
	unsigned char type_guid[PARTITION_TYPE_GUID_SIZE];
	int i, j, n;

	/* Verify that passed block has a valid GPT primary header */
	primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
	ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
					 &partition_entry_size, &header_size,
					 &max_partition_count);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Primary signature invalid cannot write GPT\n");
		goto end;
	}

	partition_0 = GET_LLWORD_FROM_BYTE(
			&primary_gpt_header[PARTITION_ENTRIES_OFFSET]);
	/* Read GPT Entries */
	for (i = 0; i < (int)(max_partition_count / 4); i++) {
		data = &primary_gpt_header[
			(partition_0 * BLOCK_SIZE) + (i * BLOCK_SIZE)];
		for (j = 0; j < 4; j++) {
			memcpy(type_guid, &data[(j * partition_entry_size)],
			       PARTITION_TYPE_GUID_SIZE);
			if (type_guid[0] == 0x00
			    && type_guid[1] == 0x00) {
				i = max_partition_count;
				break;
			}

			memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
			memcpy(UTF16_name, &data[(j * partition_entry_size) +
						 PARTITION_NAME_OFFSET],
			       MAX_GPT_NAME_SIZE);
			/*
			 * Currently partition names in *.xml are UTF-8 and lowercase
			 * Only supporting english for now so removing 2nd byte of UTF-16
			 */
			for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
				gpt_name[n] = UTF16_name[n * 2];
			}

			if (!strcmp(gpt_name, name)) {
				dprintf(INFO, "LBA %lld:%lld (%s)\n",
					GET_LLWORD_FROM_BYTE(&data
						[(j * partition_entry_size) +
						  FIRST_LBA_OFFSET]),
					GET_LLWORD_FROM_BYTE(&data
						[(j * partition_entry_size) +
						  LAST_LBA_OFFSET]),
					name);

				if (GET_LLWORD_FROM_BYTE(&data
					[(j * partition_entry_size) +
					  FIRST_LBA_OFFSET]) == first_lba &&
					GET_LLWORD_FROM_BYTE(&data
					[(j * partition_entry_size) +
					  LAST_LBA_OFFSET]) == last_lba) {
					dprintf(CRITICAL, "Already Updated\n");
					ret = 1;
					i = max_partition_count;
					break;
				}

				if (first_lba != 0ULL) {
					PUT_LONG_LONG(&data[(
						j * partition_entry_size) +
						FIRST_LBA_OFFSET], first_lba);
					PUT_LONG_LONG(&data[(
						j * partition_entry_size) +
						LAST_LBA_OFFSET], last_lba);
				}
			}
		}
	}

end:
	return ret;
}

/*
 * Update the GPT to the MMC.
 */
unsigned int
update_gpt(unsigned size, unsigned char *gptImage)
{
	unsigned int ret = 1;
	unsigned int header_size;
	unsigned long long first_usable_lba;
	unsigned long long backup_header_lba;
	unsigned int max_partition_count = 0;
	unsigned int partition_entry_size;
	unsigned int partition_entry_array_start;
	unsigned char *primary_gpt_header;
	unsigned char *secondary_gpt_header;
	unsigned int offset;
	unsigned int partition_entry_array_size;
	unsigned long long primary_header_location;	/* address on the emmc card */
	unsigned long long secondary_header_location;	/* address on the emmc card */
	unsigned long long card_capacity;

	card_capacity = mmc_get_device_capacity();

	dprintf(INFO, "update_gpt()\n");
	/* Verify that passed block has a valid GPT primary header */
	primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
	ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
					 &partition_entry_size, &header_size,
					 &max_partition_count);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Primary signature invalid cannot write GPT\n");
		goto end;
	}

	/* Get the density of the mmc device */

	/* Make secondary partition array */
	memcpy(primary_gpt_header + BLOCK_SIZE + MIN_PARTITION_ARRAY_SIZE,
			primary_gpt_header + BLOCK_SIZE,
			MIN_PARTITION_ARRAY_SIZE);

	/* Make secondary header */
	memcpy(primary_gpt_header + BLOCK_SIZE + MIN_PARTITION_ARRAY_SIZE * 2,
			primary_gpt_header,
			BLOCK_SIZE);

	/* Verify that passed block has a valid backup GPT HEADER */
	partition_entry_array_size = partition_entry_size * max_partition_count;
	if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
		partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
	}

	offset = (2 * partition_entry_array_size);
	secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;

	/* Adjust backup header */
	PUT_LONG_LONG(&secondary_gpt_header[PRIMARY_HEADER_OFFSET], (long long)0);
	PUT_LONG_LONG(&secondary_gpt_header[BACKUP_HEADER_OFFSET], (long long)1);
	PUT_LONG_LONG(&secondary_gpt_header[PARTITION_ENTRIES_OFFSET], (long long)0);

	ret =
	    partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
				&partition_entry_size, &header_size,
				&max_partition_count);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Backup signature invalid cannot write GPT\n");
		goto end;
	}

	/* Patching the primary and the backup header of the GPT table */
	patch_gpt(gptImage, card_capacity, partition_entry_array_size,
		max_partition_count, partition_entry_size, BLOCK_SIZE);

	/* Writing the primary GPT header */
	primary_header_location = PROTECTIVE_MBR_SIZE;
	ret = mmc_write(primary_header_location, BLOCK_SIZE,
			(unsigned int *)primary_gpt_header);
	if (ret) {
		dprintf(CRITICAL, "Failed to write GPT header\n");
		goto end;
	}

	/* Writing the backup GPT header */
	backup_header_lba = GET_LLWORD_FROM_BYTE
	    (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
	secondary_header_location = backup_header_lba * BLOCK_SIZE;
	ret = mmc_write(secondary_header_location, BLOCK_SIZE,
			(unsigned int *)secondary_gpt_header);
	if (ret) {
		dprintf(CRITICAL, "Failed to write GPT backup header\n");
		goto end;
	}

	/* Writing the partition entries array for the primary header */
	partition_entry_array_start = (unsigned int)(primary_gpt_header + BLOCK_SIZE);
	ret = write_gpt_partition_array(primary_gpt_header,
					partition_entry_array_start,
					partition_entry_array_size,
					BLOCK_SIZE);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Could not write GPT Partition entries array\n");
		goto end;
	}

	/*Writing the partition entries array for the backup header */
	partition_entry_array_start = (unsigned int)(primary_gpt_header + BLOCK_SIZE +
	    partition_entry_array_size);
	ret = write_gpt_partition_array(secondary_gpt_header,
					partition_entry_array_start,
					partition_entry_array_size,
					BLOCK_SIZE);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Could not write GPT Partition entries array\n");
		goto end;
	}

	/* Re-read the GPT partition table */
	dprintf(INFO, "Re-reading the GPT Partition Table\n");
	ret = mmc_boot_read_gpt(BLOCK_SIZE);
	if (ret) {
		dprintf(CRITICAL,
			"GPT: Failure to re- read the GPT Partition table\n");
		goto end;
	}
	partition_dump();
	dprintf(CRITICAL, "GPT: Partition Table written\n");
	memset(primary_gpt_header, 0x00, size);

end:
	return ret;
}

/*
 * Get backup GPT LBA
 */
unsigned int get_backup_gpt_position(unsigned long long *backup_gpt_lba)
{
	BUF_DMA_ALIGN(data, BLOCK_SIZE);
	int ret = 0;

	ret = mmc_read(PROTECTIVE_MBR_SIZE, (unsigned int *)data, BLOCK_SIZE);
	if (ret != 0)
		dprintf(CRITICAL, "Could not read primary gpt header from mmc\n");

	*backup_gpt_lba = GET_LLWORD_FROM_BYTE(&data[BACKUP_HEADER_OFFSET]);
	dprintf(CRITICAL , "get backup gpt position : %lld\n", *backup_gpt_lba);
	return ret;
}
#endif


Very few of La Paz's walls, doors and highways have escaped the touch of the spray can and brush; graffiti tags, murals and political slogans line almost every street. This phenomenon is not exclusive to Bolivia, though; it has become a distinctive trait of almost every Latin American city.
Graffiti historically belongs to underground, anti-establishment movements, and its proliferation tends to increase at times of political instability, dissatisfaction and revolution. And Latin America is a geographic area where the struggle against poverty and the fight for human rights has a tortuous history. The long-standing desire for positive change and the street art it inspires can be seen in the domain of the people where they grow up, work, play and live: in the streets.
There is no better example of a graffiti campaign aiming to inspire change than the work of Mujeres Creando, a long-standing, well-organized feminist anarchist group whose clear messages are reflected in their recognizable graffiti style. Slogans such as "Mujer! No me gusta cuando callas" (Woman! I do not like it when you are quiet) are at once critical, funny, carefully considered and, above all, provocative. In areas where there is a concentration of a specific problem (sexual assault, domestic violence), a special effort is made to make a critical, cutting message heard; otherwise, political centres, schools and thoroughfares are targets.
Mujeres Creando represent a vulnerable group in Bolivia, and they work hard to bring about a new, equitable society and unseat machismo and the patriarchy from their pedestals. It's an uphill battle, and it takes place not only within the walls of National Assembly, but in public spaces. While the aesthetic of Mujeres Creando's graffiti is important (the group's trademark firma and stylistics makes the art instantly recognizable), in the words of leading member Julieta Ojeda; 'It's not art just for the sake of art'. Their graffiti is a real, effective political weapon in their ongoing struggle.
On the eve of the presidential election, political parties have realized the potential for self-promotion on the streets and have zealously taken to them armed with brushes and paint. Alongside the blatant electoral campaigns, there can be found the political slogans of Los Satucos, made distinctive by their signature devil-tailed sign-off. The Satucos, active since 2004, are a political action group, strongly allied with the governing MAS party, yet independently run by ex-Assembly member Gustavo Torrico and a group of activists.
Other street art collectives have spoken out against the Satucos, claiming that the group has nothing in common with the unfunded, spontaneous work of street artists and graffitists such as Knorke Leaf, and that the Satucos' prolific and extensive presence on the city walls is an intrusion into what is rightfully a space reserved for the people's voices. The Satucos are seen by many as political propagandists, thinly veiling themselves as an underground movement in order to benefit from the exposure which the open stage of the streets offer.
Yet, there appears to be a universal consensus that if you are creating debate and ideas with your work, making people think about what you have written, then this is a form of art and therefore its presence on the city walls is ultimately a force for good. I asked Torrico for his opinion on the various graffiti campaigns, and what emerged straight away was his genuine enthusiasm, support and utmost respect for the street art of La Paz; 'La Paz would be a horrible place without street art'. Indeed, he argues that since the graffiti of the Satucos is always positive in tone, never slanderous and, above all, creative in its use of puns and wordplay. Reflecting on whether their work can be considered art, he believes that these slogans earn their place on the walls of La Paz because they stimulate debate and make people think. 'What makes us happy is that we have revolutionized, but above all, reclaimed the streets as a political mural', Torrico said, 'which can be opposed to or supportive of a political cause'.
It appears to me that all these various groups share two key beliefs: the superiority of creative expression for stimulating change, and people's right to have their voices heard on the streets of the city. What divides them is their definition of who the people of La Paz are. For Torrico, the streets are a manifestation of the right to freedom of speech, but for the street art collectives, for the independent graffiti artist and groups such as the Mujeres Creando, the political parties whose voices already permeate every nook and cranny of the country are invading the only platform open to those without the power and money to have their voices heard anywhere else. The streets are where democracy is at its purest.
The result is a city whose streets are resounding with silent shouting. In the Evo Morales era, there is an atmosphere of revolution: political revolution from the government and the anti-establishment groups, social and cultural revolution from the likes of the Mujeres Creando and the street artists. Scrawled all over El Alto is the phrase 'My city is changing.' Is it?


Looking for Davie roofers that can be trusted? We are the leading roofing contractors in the city. Call us today for an estimate.
Many Davie Roofers tend to offer tantalizing prices and various attractive roofing packages to the city's residents. However, where many fall short is in the quality of their service. Some roofing contractors may price their services very high so as to appear that they are offering an excellent service. That said an expensive roofing service isn't necessarily great and the same can be said for a budget service. So, when hiring a roofing company in Davie it is essential to check reviews and feedback. We are one of the most reputed roofing services in the city with hundreds of satisfied clients and counting. Plus, we are priced competitively without any compromise to the quality of materials used or workmanship.
Which is the Best Roofing Company in Davie?
Victory Roofing Contractors is a leading roofing contractor in Davie. We provide many different services which include tile roofs, flat roof and shingle roof installation, and repair. We are a full-service company which means that we provide just about every roofing service you'll need.
Each member of our team is a seasoned expert and has been with us for years. As a family-owned company, we make sure to vet each recruit and put them through training. Plus, all employees are certified, insured and bonded. So, you're not just getting quality roofing but expert Davie roofers.
Workmanship with a Satisfaction Guarantee!
We are one of the few Davie roofers who are proud to back the work we do with a warranty. Our warranty covers the work we do and the materials we use. If you are not satisfied for whatever reason with the quality, we will do it again or continue to work. However, we have never encountered a client who was not happy with the quality of our work. On the contrary, many have commented that ours is the best they have seen.
In addition to top quality workmanship we also offer excellent customer service. Each team member is obliged to answer your questions. Our goal is to keep you in the loop throughout a new metal roof installation, the installation of shingles roof or any other type of work.
Looking for Davie roofers whom you can trust? Want to hire a company that does not waste your time and money? Then call our experts today. We will provide you with an estimate and answer any questions you may have.
Victory Roofing is one of the best companies I've used. They are responsive, knowledgeable, experienced, efficient, courteous and prompt.
Just finished our roof and it came out great. There were no hidden costs or messing around. Was very professional and knocked out our job really fast.
They came out and installed new windows for us about a year ago. We had a warranty issue and they came out and fixed it.
Arrived and finished on time, high quality materials. Respectful of our landscaping and property and left our driveway exactly as they'd found it. Roof looks great too! Thanks for all your great work.
Victory Roofing is the only company my family will use when we have roofing problems. They work fast and never really over charge. The workers all know exactly what they are doing and make sure to talk me through whatever I am having done. Satisfied customer here!
Tom made everything very easy! They were super friendly when they called and the service team worked quickly and cleanup up great! Will definitely use them again!


text:
how dark
A quick guide to a growing force in U.S. politics
News coverage of dark money from MapLight
Tools for investigating dark money
How dark money works
This Week In Local Dark Money News
September 16, 2016 | dark money watch | Margaret Sessa-Hawkins
When it comes to dark money — money spent trying to influence voters by groups that do not disclose their donors — the focus is often on the federal level. But a considerable amount of dark money is also going to state and local elections. Our weekly roundup looks at dark money spending at the state and federal levels.
The Guardian obtained a series of documents detailing how Wisconsin Governor Scott Walker's recall campaign encouraged some wealthy individuals to support him by contributing to an outside spending group that acted as a "shadow campaign committee." Wisconsin prosecutors assembled the documents as part of an investigation into possible campaign finance violations. The conservative state Supreme Court stopped the investigation, declaring that prosecutors had misunderstood the state's campaign finance laws, and ordered the documents be destroyed. However, the files were leaked to The Guardian. The papers show that Walker's campaign frequently told donors to give their money to Wisconsin Club For Growth, a conservative social welfare organization that can accept unlimited donations without disclosing its donors. Prosecutors, who argued that funneling the contributions through the group violated state and federal laws, have filed an appeal with the U.S. Supreme Court. The high court is expected to announce soon whether it will take the case.
Dark money is flowing to state judicial contests, according to a new study of primary races by The Brennan Center for Justice. "Polling shows that 95 percent of the public believes campaign spending influences how judges rule in cases," said Alicia Bannon, Senior Counsel in the Democracy Program at the Brennan Center. "With the rise of outside spenders that do not disclose their donors, we can't even identify potential conflicts of interest. This poses a major threat to the integrity of our justice system." The Brennan Center will be posting periodic information and analysis on those races on their Supreme Court Elections page.
A Florida state appeals court issued a temporary decree Thursday that keeps a measure restricting campaign contributions off Miami-Dade County's November ballot, The Miami Herald reports. The measure would have banned contractors who do work for the county and their lobbyists from donating to most candidates for county office and limit campaign contributions to $250. County commissioners had initially voted to keep the measure off the ballot, but a lower court judge last week ruled that "elected commissioners, whose reelection efforts thrive on lobbyist and vendor donations, could not block the petition drive." County lawyers immediately appealed the ruling, and a stay was in effect until the appeals court issued its decision. Opponents of the measure say that the court's decision not to lift the stay, although temporary, is a clear indication of the judges' final ruling.
Outside groups spent nearly half a million dollars on New Hampshire's Tuesday primary races, according to New Hampshire Public Radio. The vast majority of that money — $431,941 — was spent on the governor's race. Colin Van Ostern, who won the Democratic gubernatorial primary, received $259618 in support from outside groups, including a joint donation to him and Republican candidate Jeanie Forrester. Forrester received $226,921 in support from outside groups and placed fourth in the Republican gubernatorial primary. Executive Councilor Chris Sununu was declared the winner of that race Wednesday, when state Representative Frank Edelblut conceded. Edelblut was within 1,000 votes of Sununu, and could have asked for a recount, but did not. Outside groups also spent $67,115 supporting state legislative candidates.
more news coverage
brought to you by maplight, a nonpartisan research organization that tracks money in politics, and our partners.
Contact Us|Donate

redpajama_set_name: RedPajamaCommonCrawl


text:
RetailShark Tank
The 15 Biggest 'Shark Tank' Success Stories of All Time
Entrepreneurs who make it onto a "Shark Tank" episode have the opportunity to introduce their company to a viewing audience of 7 million potential customers.
The companies that land a deal with one or more of the show's investors then have the chance to scale and, in some cases, become a nationally recognized brand.
We looked through old episodes and asked the Sharks themselves about their most successful deals. Read on to learn about the biggest "Shark Tank" success stories so far.
Scrub Daddy/Facebook
A sponge company has far and away become the biggest "Shark Tank" success story. Over the past three years, Scrub Daddy has brought in a total of $75 million in revenue, according to investor Lori Greiner.
Greiner made a deal with its founder and CEO, Aaron Krause, in Season 4 for $200,000 in exchange for 20% equity. At that point, Krause had struggled to reach $100,000 in sales over 18 months, but Greiner saw great potential in the company's signature offering, a proprietary smiley-faced sponge that was more durable, hygienic, and effective than a traditional one.
She helped Krause expand his product line and brought them onto QVC and into stores like Bed, Bath & Beyond, where they have become bestsellers.
A man from Lubbock, TX believes his colorful, magnetic light strands hold the solution to one of the holiday's biggest headachesKelsey McNeal ABC via Getty Images
When Robert Herjavec invested $100,000 for 10% of Evan Mendelsohn and Nick Morton's ugly Christmas-sweater company in Season 4, it could seem to viewers that he was betting on a fleeting fad. It turned out, though, to be his most profitable "Shark Tank" investment, he told Business Insider.
To stay ahead of trends, Herjavec helped make Tipsy Elves a year-round novelty apparel company that can capitalize off multiple holidays and college-football season.
Before its 2013 "Shark Tank" appearance, Tipsy Elves made $900,000 in annual revenue. Last year it brought in around $8 million, and this year it's on track to make $12 million, according to the company.
Breathometer
Kelsey McNeal ABC via Getty Images
In Season 5, Charles Yim got a five-Shark deal for Breathometer, a portable Breathalyzer that works with a smartphone. Mark Cuban, Kevin O'Leary, Daymond John, Herjavec, and Greiner got in on a $650,000 deal for 30% of the company.
Since his "Shark Tank" appearance, Yim secured an additional $6.5 million in funding, partnered with the prestigious Cleveland Clinic, and developed a more accurate and more portable main product in addition to a device that tracks oral health and hydration levels.
Yim told Inc. that Breathometer is expected to end 2015 with $20 million in sales — double last year's number.
Bubba's-Q Boneless Ribs
A former pro football player from Avon, Ohio tries to sell the Sharks on his delicious boneless baby back ribs which can be cooked in 2 minutes in the microwave.Michael Ansell ABC via Getty Images
Al "Bubba" Baker, 1978 NFL Defensive Rookie of the Year, secured a deal with John in Season 5 for $300,000 in exchange for 30% equity in and licensing rights to his company, Bubba's-Q Boneless Ribs.
John told Business Insider that as someone who built a career in fashion, he never expected that his most profitable investment would be in a rib business.
John helped Baker secure a deal with a large-scale food processing plant and said he thinks he can soon get Bubba's-Q to become a national brand with $200 million in lifetime sales.
Grace and Lace
Shark Tank/ABC
In Season 5, Barbara Corcoran invested $175,000 for 10% of husband-and-wife duo Melissa and Rick Hinnant's fashion company Grace and Lace. Corcoran told Business Insider that it's her most profitable "Shark Tank" investment.
Ten Thirty One Productions
Before their appearance, the Hinnants brought in about $1 million in sales. They are now expecting $6.5 million this year, a boost helped by an appearance in Cosmopolitan magazine.
As the company has grown, its philanthropic mission has as well, and since appearing on the show it has used profits to open two orphanages in India, housing a total of 100 kids.
In Season 5, Cuban decided to put up $2 million for 20% of Melissa Carbone's live horror-entertainment company Ten Thirty One Productions.
Last year the company brought in $3 million in revenue, and although he did not disclose an exact number, Cuban told us it is making at least half a million dollars in annual profit.
Ten Thirty One had another successful Halloween season this year in its birthplace of Los Angeles, but struggled in its expansion to New York City due to a lack of preparation for storm conditions. Carbone said it was a stressful but valuable learning experience, and she looks forward to expanding to Cuban's hometown, Dallas, next year.
Tracey Noonan and Danielle Vilagie are a mother-daughter duo from Boston with a company that makes cupcakes in a jar. In Season 4, they made a deal with O'Leary in which he invested $75,000 for royalties instead of equity. He made $1 from every cupcake sold until he made his money back, and then began receiving 50 cents per cupcake sold.
Since its appearance on the show, Wicked Good Cupcakes has expanded to a new production facility and a couple of new locations.
O'Leary said it's been his most profitable investment of the show, and since Noonan and Vilagie appeared, they've gone from around $7,000 in monthly sales to $400,000, or about $4.8 million annually.
Cuban and Herjavec split a $1.2 million investment for 10% equity in Diana and Josh Harbour's online women's fashion retailer The Red Dress Boutique in Season 6, with Cuban taking the lead advisory role.
In the week following their television appearance, the husband-and-wife team brought in $1 million in sales, but also couldn't keep up with demand. Cuban helped them with infrastructure issues, and last year they brought in $14 million in revenue.
Cuban said it's making at least half a million dollars in annual profit.
In Season 6, Bombas cofounders gave John a 17.5% stake in their company for $200,000. It is an online-only athletic sock company that donates a pair of socks to a homeless shelter for every pair sold.
Bombas' founders told radio host Jason Bax that they sold $400,000 of socks in the four days after their television appearance and ended 2014 with $2 million in sales.
John said it is one of his most profitable investments.
Simple Sugars
Adam Taylor ABC via Getty Images
Lani Lazzari was just 18 when she entered the tank in Season 4 to pitch her skincare company Simple Sugars. She ended up making a deal with Cuban for $100,000 in return for 33% equity.
Within just 24 hours of her episode's premiere, Lazzari's sales jumped to $220,000 from $50,000, and she hit $1 million six weeks later. Today Simple Sugars products are in more than 700 retail locations and ship internationally.
Last year the company brought in more than $3 million in revenue, and Cuban said it's one of his most profitable investments from the show.
Groovebook
Husband-and-wife team Brian and Julie Whiteman came into the tank in Season 3 to present GrooveBook, a digital-photo subscription service. For $2.99 a month, users get a bound book of high-resolution photos they took with their smartphones. The founders made a deal with Cuban and O'Leary for $150,000 in exchange for 80% of licensing profits, with O'Leary taking the lead advisory role.
Not only did the Whitemans gain 50,000 subscribers shortly after the premiere of their episode, but last November, the publicly traded company Shutterfly bought GrooveBook for $14.5 million.
Cousins Maine Lobster
Cousins Sabin Lomac and Jim Tselikis shipped lobster from their home state of Maine to their new home in California and started a high-end food truck named Cousins Maine Lobster, which became known for its lobster rolls. The cousins made a deal with Corcoran for $55,000 in exchange for 15% of their company in Season 4.
Shortly after their episode premiered, the company hit $700,000 in sales. Last year they brought in $8 million in revenue, according to Entrepreneur.
Former Navy SEAL Eli Crane and his wife and business partner Jen made a deal with Cuban and O'Leary for $150,000 in exchange for a 20% stake in Bottle Breacher, a company staffed by military veterans who turn dummy .50-caliber bullets into stylized bottle openers.
O'Leary has taken the lead brand ambassador role and said it's one of his most profitable investments. It's continued to grow to meet increasing demand, and has made more than $2.5 million in sales this year.
Herjavec invested $350,000 for 10% of Max Gunawan's foldable, magnetic-lamp company Lumio in Season 6 after calling him "possibly the best entrepreneur" he had seen so far on the show.
Last year Lumio made $3 million in sales, hitting that mark again this past June, he told Forbes. He explained that his growth is healthy and that he will continue to make distribution deals with stores that appeal to a high-end, artistic audience.
Readerest
Rick Hopper essentially handed the reins of ReadeRest over to Greiner when he agreed to a $150,000 investment in exchange for 65% of the company in Season 3, but it turned his little one-man show into a huge success.
The product, a magnetic clip that holds eyeglasses in place on a shirt, regularly sells out on QVC. Readerest says it's made $13 million in revenue in the three years following the "Shark Tank" appearance.
This article originally appeared on Business Insider.


As my former collegue could express really well: 'India, oh India'. Every time you visit India there is a new trend visible. It's unbelievable how fast a big country like India is changing in every way. But what are the actual trends and what are the hypes?
With 1.5 billion persons in India it's hard to keep up with the development of India. But what is are the consumer trends in India? What are the business trends in India? What are the major city trends? Basicaly: What is happening in India?
In this keynote i will guide you as a trendwatcher India. You will get up to date with the latest trends and hypes in the beautiful country of India.
Latest trends and hypes for the city area.
Political system and changes in it.
The latest laws and legalizations.
Getting fully up to date with India.


In this article, I am going to inform you about the importance of responsive web design. Incase you are unaware, when I refer to responsive web design, then it's vital that you study this article.
Responsive web design is different from ordinary web design. A responsive site has the ability to automatically adjust in accordance to a users screen dimensions. For example; when a website visitor accesses your website using any device other than traditional means, such as a desktop computer or laptop. The technical elements of a responsive website are what causes the site to automatically arrange itself to display your content professionally.
Do you own a traditional website? It's more than likely users that visit your site using modern devices, such as mobile phones or tablets will incorporate a poor user experience. If you don't know what your website looks like on a mobile or tablet device, then check it now. Common issues of non-responsive websites often include; poor layout, minute content, broken functions and awful navigation.
Several years back, a responsive website wasn't required. Everything has changed online, a responsive website is a must.
Fancy numbers aren't required to explain the importance of a responsive website. Review your current daily activities; do you access emails, the internet or social media sites using anything other than your laptop or desktop? Then you must have experienced the pitfalls of a website that isn't responsive. It's frustrating to use a badly laid out site, isn't it.
Please ask yourself this question; "Have you gone back to a website where you had a poor user experience?" It's more than likely that you haven't. But why? The reason that you haven't revisited a non-mobile or tablet compatible website is because you have remembered how bad your experience was the last time you visited that site. What you probably don't realize – until reading this article, is that if your customers have a bad experience visiting your website, it's more than likely that they won't visit your website again either.
If you don't have a responsive website at present, I really do hope that these points highlight the urgency for you to contact your web developer.
Some marketing managers and business owners have asked me whether a mobile site would be a more cost effective solution. Unfortunately a mobile site is not going to solve your issues. A mobile website will not be dissimilar to getting a hole in your ship and filling it with a cork.
The floods may stop, but there is still an ever-going issue that requires regular maintenance.
In summary, I suggest that you test your current website, if it's ok 'for now' then leave it. If the usability is at all questionable, then I strongly suggest to consider a responsive website. And remember that a mobile site is not a long-term solution!