Index: uspace/lib/gpt/libgpt.c
===================================================================
--- uspace/lib/gpt/libgpt.c	(revision c3cbbb2a143977e56be842336794a3a84e70279d)
+++ uspace/lib/gpt/libgpt.c	(revision 283ea3df7cc3e9b7243de7f2c4161296bc34121f)
@@ -51,11 +51,11 @@
 #include "libgpt.h"
 
-static int load_and_check_header(service_id_t handle, aoff64_t addr, size_t b_size, gpt_header_t *header);
-static gpt_partitions_t * alloc_part_array(uint32_t num);
+static int load_and_check_header(service_id_t, aoff64_t, size_t, gpt_header_t *);
+static gpt_partitions_t * alloc_part_array(uint32_t);
 static int extend_part_array(gpt_partitions_t *);
 static int reduce_part_array(gpt_partitions_t *);
-static long long nearest_larger_int(double a);
+//static long long nearest_larger_int(double);
 static uint8_t get_byte(const char *);
-static int check_overlap(gpt_part_t * p1, gpt_part_t * p2);
+static bool check_overlap(gpt_part_t *, gpt_part_t *);
 
 /** Allocate memory for gpt label */
@@ -66,6 +66,13 @@
 		return NULL;
 	
+	/* This is necessary so that gpt_part_foreach does not segfault */
+	label->parts = gpt_alloc_partitions();
+	if (label == NULL) {
+		free(label);
+		return NULL;
+	}
+	
 	label->gpt = NULL;
-	label->parts = NULL;
+	
 	label->device = 0;
 	
@@ -92,7 +99,8 @@
 		return NULL;
 	
-	// We might need only sizeof(gpt_header_t),
-	// but we should follow specs and have
-	// zeroes through all the rest of the block
+	/* 
+	 * We might need only sizeof(gpt_header_t), but we should follow 
+	 * specs and have zeroes through all the rest of the block
+	 */
 	size_t final_size = size > sizeof(gpt_header_t) ? size : sizeof(gpt_header_t);
 	gpt->header = malloc(final_size);
@@ -178,24 +186,14 @@
 	int rc;
 	size_t b_size;
-
-	label->gpt->header->header_crc32 = 0;
-	label->gpt->header->header_crc32 = compute_crc32((uint8_t *) label->gpt->header,
-					uint32_t_le2host(label->gpt->header->header_size));
-
-	rc = block_init(EXCHANGE_ATOMIC, dev_handle, b_size);
+	
+	/* The comm_size argument (the last one) is ignored */
+	rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096);
 	if (rc != EOK && rc != EEXIST)
 		return rc;
-
+	
 	rc = block_get_bsize(dev_handle, &b_size);
 	if (rc != EOK)
 		return rc;
-
-	/* Write to main GPT header location */
-	rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, label->gpt->header);
-	if (rc != EOK) {
-		block_fini(dev_handle);
-		return rc;
-	}
-
+	
 	aoff64_t n_blocks;
 	rc = block_get_nblocks(dev_handle, &n_blocks);
@@ -204,12 +202,48 @@
 		return rc;
 	}
-
+	
+	uint64_t tmp;
+	
+	/* Prepare the backup header */
+	label->gpt->header->alternate_lba = label->gpt->header->my_lba;
+	label->gpt->header->my_lba = host2uint64_t_le(n_blocks - 1);
+	
+	tmp = label->gpt->header->entry_lba;
+	label->gpt->header->entry_lba = host2uint64_t_le(n_blocks - 
+	    (uint32_t_le2host(label->gpt->header->fillries) * sizeof(gpt_entry_t)) 
+	    / b_size - 1);
+	
+	label->gpt->header->header_crc32 = 0;
+	label->gpt->header->header_crc32 = host2uint32_t_le( 
+	    compute_crc32((uint8_t *) label->gpt->header,
+	        uint32_t_le2host(label->gpt->header->header_size)));
+	
 	/* Write to backup GPT header location */
-	//FIXME: those idiots thought it would be cool to have these fields in reverse order...
 	rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, label->gpt->header);
+	if (rc != EOK) {
+		block_fini(dev_handle);
+		return rc;
+	}
+	
+	
+	/* Prepare the main header */
+	label->gpt->header->entry_lba = tmp;
+	
+	tmp = label->gpt->header->alternate_lba;
+	label->gpt->header->alternate_lba = label->gpt->header->my_lba;
+	label->gpt->header->my_lba = tmp;
+	
+	label->gpt->header->header_crc32 = 0;
+	label->gpt->header->header_crc32 = host2uint32_t_le( 
+	    compute_crc32((uint8_t *) label->gpt->header,
+	        uint32_t_le2host(label->gpt->header->header_size)));
+	
+	/* Write to main GPT header location */
+	rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, label->gpt->header);
 	block_fini(dev_handle);
 	if (rc != EOK)
 		return rc;
-
+	
+	
 	return 0;
 }
@@ -218,5 +252,5 @@
 gpt_partitions_t * gpt_alloc_partitions()
 {
-	return alloc_part_array(128);
+	return alloc_part_array(GPT_MIN_PART_NUM);
 }
 
@@ -241,7 +275,4 @@
 	}
 
-	/* We can limit comm_size like this:
-	 *  - we don't need more bytes
-	 *  - the size of GPT partition entry can be different to 128 bytes */
 	/* comm_size is ignored */
 	rc = block_init(EXCHANGE_SERIALIZE, label->device, sizeof(gpt_entry_t));
@@ -258,14 +289,18 @@
 	aoff64_t pos = ent_lba * block_size;
 
-	/* Now we read just sizeof(gpt_entry_t) bytes for each entry from the device.
+	/* 
+	 * Now we read just sizeof(gpt_entry_t) bytes for each entry from the device.
 	 * Hopefully, this does not bypass cache (no mention in libblock.c),
 	 * and also allows us to have variable partition entry size (but we
 	 * will always read just sizeof(gpt_entry_t) bytes - hopefully they
-	 * don't break backward compatibility) */
+	 * don't break backward compatibility) 
+	 */
 	for (i = 0; i < fillries; ++i) {
-		//FIXME: this does bypass cache...
+		/*FIXME: this does bypass cache... */
 		rc = block_read_bytes_direct(label->device, pos, sizeof(gpt_entry_t), label->parts->part_array + i);
-		//FIXME: but seqread() is just too complex...
-		//rc = block_seqread(gpt->device, &bufpos, &buflen, &pos, res->part_array[i], sizeof(gpt_entry_t));
+		/* 
+		 * FIXME: but seqread() is just too complex...
+		 * rc = block_seqread(gpt->device, &bufpos, &buflen, &pos, res->part_array[i], sizeof(gpt_entry_t));
+		 */
 		pos += ent_size;
 
@@ -274,5 +309,6 @@
 	}
 
-	/* FIXME: so far my boasting about variable partition entry size
+	/*
+	 * FIXME: so far my boasting about variable partition entry size
 	 * will not work. The CRC32 checksums will be different.
 	 * This can't be fixed easily - we'd have to run the checksum
@@ -333,6 +369,12 @@
 		goto fail;
 	
+	uint64_t arr_blocks = (fillries * sizeof(gpt_entry_t)) / b_size;
+	label->gpt->header->first_usable_lba = host2uint64_t_le(arr_blocks + 1);
+	label->gpt->header->last_usable_lba = host2uint64_t_le(n_blocks - arr_blocks - 2);
+	
+	
 	/* Write to backup GPT partition array location */
-	//rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, header->raw_data);
+	rc = block_write_direct(dev_handle, n_blocks - arr_blocks - 1, 
+	         arr_blocks, label->parts->part_array);
 	if (rc != EOK)
 		goto fail;
@@ -340,6 +382,5 @@
 	/* Write to main GPT partition array location */
 	rc = block_write_direct(dev_handle, uint64_t_le2host(label->gpt->header->entry_lba),
-	         nearest_larger_int((uint64_t_le2host(label->gpt->header->entry_size) * fillries) / b_size),
-	         label->parts->part_array);
+	         arr_blocks, label->parts->part_array);
 	if (rc != EOK)
 		goto fail;
@@ -442,11 +483,5 @@
 int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
 {
-	if (label->parts->fill == label->parts->arr_size) {
-		if (extend_part_array(label->parts) == -1)
-			return ENOMEM;
-	}
-	
-	/*FIXME:
-	 * Check dimensions and stuff! */
+	/* FIXME: Check dimensions! */
 	gpt_part_foreach(label, p) {
 		if (gpt_get_part_type(p) != GPT_PTE_UNUSED) {
@@ -456,7 +491,18 @@
 	}
 	
-	memcpy(label->parts->part_array + label->parts->fill++,
-	       partition, sizeof(gpt_part_t));
-	
+	gpt_part_t *p;
+	/* Find the first empty entry */
+	do {
+		if (label->parts->fill == label->parts->arr_size) {
+			if (extend_part_array(label->parts) == -1)
+				return ENOMEM;
+		}
+		
+		p = label->parts->part_array + label->parts->fill++;
+		
+	} while (gpt_get_part_type(p) != GPT_PTE_UNUSED);
+	
+	
+	memcpy(p, partition, sizeof(gpt_entry_t));
 	
 	
@@ -475,20 +521,27 @@
 int gpt_remove_partition(gpt_label_t *label, size_t idx)
 {
-	if (idx >= label->parts->fill)
+	if (idx >= label->parts->arr_size)
 		return EINVAL;
 	
-	/* FIXME! 
+	/* 
+	 * FIXME! 
 	 * If we allow blank spots, we break the array. If we have more than
 	 * 128 partitions in the array and then remove something from
-	 * the first 128 partitions, we would forget to write the last one.*/
+	 * the first 128 partitions, we would forget to write the last one.
+	 */
 	memset(label->parts->part_array + idx, 0, sizeof(gpt_entry_t));
 	
-	label->parts->fill = idx;
-	
-	/* FIXME! HOPEFULLY FIXED.
+	if (label->parts->fill > idx)
+		label->parts->fill = idx;
+	
+	/* 
+	 * FIXME! HOPEFULLY FIXED.
 	 * We cannot reduce the array so simply. We may have some partitions
-	 * there since we allow blank spots. */
+	 * there since we allow blank spots. 
+	 */
 	gpt_part_t * p;
-	if (label->parts->fill < (label->parts->arr_size / 2) - GPT_IGNORE_FILL_NUM) {
+	
+	if (label->parts->fill > GPT_MIN_PART_NUM &&
+	    label->parts->fill < (label->parts->arr_size / 2) - GPT_IGNORE_FILL_NUM) {
 		for (p = gpt_get_partition_at(label, label->parts->arr_size / 2); 
 		     p < label->parts->part_array + label->parts->arr_size; ++p) {
@@ -635,4 +688,7 @@
 }
 
+/** Generate a new pseudo-random UUID
+ * @param uuid Pointer to the UUID to overwrite.
+ */
 void gpt_set_random_uuid(uint8_t * uuid)
 {
@@ -645,5 +701,12 @@
 }
 
-// Internal functions follow //
+/** Get next aligned address */
+uint64_t gpt_get_next_aligned(uint64_t addr, unsigned int alignment)
+{
+	uint64_t div = addr / alignment;
+	return (div + 1) * alignment;
+}
+
+/* Internal functions follow */
 
 static int load_and_check_header(service_id_t dev_handle, aoff64_t addr, size_t b_size, gpt_header_t * header)
@@ -686,5 +749,5 @@
 		return NULL;
 	}
-
+	
 	uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
 	res->part_array = malloc(size * sizeof(gpt_entry_t));
@@ -694,5 +757,7 @@
 		return NULL;
 	}
-
+	
+	memset(res->part_array, 0, size * sizeof(gpt_entry_t));
+	
 	res->fill = 0;
 	res->arr_size = num;
@@ -727,5 +792,5 @@
 			return ENOMEM;
 
-		memcpy(tmp, p->part_array, p->fill < nsize ? p->fill  : nsize);
+		memcpy(tmp, p->part_array, p->fill < nsize ? p->fill : nsize);
 		free(p->part_array);
 		p->part_array = tmp;
@@ -736,6 +801,5 @@
 }
 
-//FIXME: replace this with a library call, if it exists
-static long long nearest_larger_int(double a)
+/*static long long nearest_larger_int(double a)
 {
 	if ((long long) a == a) {
@@ -744,6 +808,9 @@
 
 	return ((long long) a) + 1;
-}
-
+}*/
+
+/* Parse a byte from a string in hexadecimal 
+ * i.e., "FF" => 255 
+ */
 static uint8_t get_byte(const char * c)
 {
@@ -755,14 +822,14 @@
 }
 
-static int check_overlap(gpt_part_t * p1, gpt_part_t * p2)
+static bool check_overlap(gpt_part_t * p1, gpt_part_t * p2)
 {
 	if (gpt_get_start_lba(p1) < gpt_get_start_lba(p2) && gpt_get_end_lba(p1) <= gpt_get_start_lba(p2)) {
-		return 0;
+		return false;
 	} else if (gpt_get_start_lba(p1) > gpt_get_start_lba(p2) && gpt_get_end_lba(p2) <= gpt_get_start_lba(p1)) {
-		return 0;
-	}
-
-	return 1;
-}
-
-
+		return false;
+	}
+
+	return true;
+}
+
+
