Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 24e58cc0ff53327f65d95ecaa6c8b745606ba2f0)
+++ uspace/lib/c/Makefile	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -63,4 +63,5 @@
 	generic/cap.c \
 	generic/cfg.c \
+	generic/checksum.c \
 	generic/clipboard.c \
 	generic/corecfg.c \
Index: uspace/lib/c/generic/checksum.c
===================================================================
--- uspace/lib/c/generic/checksum.c	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/c/generic/checksum.c	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <checksum.h>
+
+/** This is 256-value table of precomputed polynomials for CRC32. Note
+ *  the values depend on the selected divisor polynomial (currently
+ *  0xedb88320) and whether the CRC computation is reflected or not.
+ *  See http://www.repairfaq.org/filipg/LINK/F_crc_v3.html for a perfect
+ *  source of info about this.
+ */
+uint32_t poly_table[256] =
+{
+	0,			0x77073096, 0xEE0E612C, 0x990951BA,
+	0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+	0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+	0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+	0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+	0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
+	0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
+	0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+	0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
+	0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
+	0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+	0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
+	0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+	0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+	0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
+	0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
+	0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+	0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+	0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
+	0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+	0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
+	0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
+	0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+	0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
+	0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+	0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+	0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
+	0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+	0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+	0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
+	0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
+	0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+	0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+/** Computes CRC32 value.
+ * @param[in] data		Pointer to the beginning of data to process.
+ * @param[in] length	Length of the data in bytes.
+ * 
+ * @return		The computed CRC32 of the data.
+ * 
+ * Note: see wiki.osdev.org/CRC32 for reference.
+ */
+uint32_t compute_crc32(uint8_t * data, size_t length)
+{
+	uint32_t seed = 0x0;
+	
+	return compute_crc32_seed(data, length, seed);
+}
+
+/** Computes CRC32 value with initial seed.
+ * Use this when checksumming not continous data (linked lists, trees,
+ * etc.). On the first data block call compute_crc32() and use the result
+ * as the seed for the following call of compute_crc32_seed() on the next
+ * block. Then use the result of that call as the seed of the following
+ * call, etc. 
+ * 
+ * @param[in] data		Pointer to the beginning of data to process.
+ * @param[in] length	Length of the data in bytes.
+ * @param[in] seed		The starting value of the CRC.
+ * 
+ * @return		The computed CRC32 of the data of all the previous
+ * 				blocks together.
+ * 
+ */
+uint32_t compute_crc32_seed(uint8_t * data, size_t length, uint32_t seed)
+{
+	uint32_t crc = ~seed;
+	for (;length !=0; --length)
+		crc = poly_table[((uint8_t) crc ^ *(data++))] ^ (crc >> 8);
+
+	return (~crc);
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/checksum.h
===================================================================
--- uspace/lib/c/include/checksum.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/c/include/checksum.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_CHECKSUM_H_
+#define LIBC_CHECKSUM_H_
+
+#include <sys/types.h>
+
+extern uint32_t compute_crc32(uint8_t *, size_t);
+extern uint32_t compute_crc32_seed(uint8_t *, size_t, uint32_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/gpt/Makefile
===================================================================
--- uspace/lib/gpt/Makefile	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/gpt/Makefile	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2011 Dominik Taborsky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBMBR_PREFIX)
+LIBRARY = libgpt
+
+SOURCES = \
+	libgpt.c \
+	global.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/gpt/global.c
===================================================================
--- uspace/lib/gpt/global.c	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/gpt/global.c	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libgpt
+ * @{
+ */
+/** @file
+ */
+
+#include "libgpt.h"
+
+/** GPT header signature ("EFI PART" in ASCII) */
+const uint8_t efi_signature[8] = {
+	0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
+};
+
+const uint8_t revision[4] = {
+	00, 00, 01, 00
+};
+
+const struct partition_type gpt_ptypes[] = {
+	{ "Unused entry",					"00000000" "0000" "0000" "0000000000000000" }, /* 0 */
+	{ "HelenOS System",					"656C6548" "4F6E" "5320" "53797374656D0000" }, /* 1 It says "HelenOS System\0\0" */
+	{ "MBR partition scheme",			"024DEE41" "33E7" "11D3" "9D690008C781F39F" },
+	{ "EFI System",						"C12A7328" "F81F" "11D2" "BA4B00A0C93EC93B" },
+	{ "BIOS Boot",						"21686148" "6449" "6E6F" "744E656564454649" },
+	{ "Windows Reserved",				"E3C9E316" "0B5C" "4DB8" "817DF92DF00215AE" },
+	{ "Windows Basic data",				"EBD0A0A2" "B9E5" "4433" "87C068B6B72699C7" },
+	{ "Windows LDM metadata", 			"5808C8AA" "7E8F" "42E0" "85D2E1E90434CFB3" },
+	{ "Windows LDM data", 				"AF9B60A0" "1431" "4F62" "BC683311714A69AD" },
+	{ "Windows Recovery Environment",	"DE94BBA4" "06D1" "4D40" "A16ABFD50179D6AC" },
+	{ "Windows IBM GPFS",				"37AFFC90" "EF7D" "4E96" "91C32D7AE055B174" }, /* 10 */
+	{ "Windows Cluster metadata",		"DB97DBA9" "0840" "4BAE" "97F0FFB9A327C7E1" },
+	{ "HP-UX Data",						"75894C1E" "3AEB" "11D3" "B7C17B03A0000000" },
+	{ "HP-UX Service",					"E2A1E728" "32E3" "11D6" "A6827B03A0000000" },
+	{ "Linux filesystem data",			"0FC63DAF" "8483" "4772" "8E793D69D8477DE4" },
+	{ "Linux RAID",						"A19D880F" "05FC" "4D3B" "A006743F0F84911E" },
+	{ "Linux Swap",						"0657FD6D" "A4AB" "43C4" "84E50933C84B4F4F" },
+	{ "Linux LVM",						"E6D6D379" "F507" "44C2" "A23C238F2A3DF928" },
+	{ "Linux filesystem data",			"933AC7E1" "2EB4" "4F13" "B8440E14E2AEF915" },
+	{ "Linux Reserved",					"8DA63339" "0007" "60C0" "C436083AC8230908" },
+	{ "FreeBSD Boot",					"83BD6B9D" "7F41" "11DC" "BE0B001560B84F0F" }, /* 20 */
+	{ "FreeBSD Data",					"516E7CB4" "6ECF" "11D6" "8FF800022D09712B" },
+	{ "FreeBSD Swap",					"516E7CB5" "6ECF" "11D6" "8FF800022D09712B" },
+	{ "FreeBSD UFS", 					"516E7CB6" "6ECF" "11D6" "8FF800022D09712B" },
+	{ "FreeBSD Vinum VM",				"516E7CB8" "6ECF" "11D6" "8FF800022D09712B" },
+	{ "FreeBSD ZFS",					"516E7CBA" "6ECF" "11D6" "8FF800022D09712B" },
+	{ "Mac OS X HFS+",					"48465300" "0000" "11AA" "AA1100306543ECAC" },
+	{ "Mac OS X UFS",					"55465300" "0000" "11AA" "AA1100306543ECAC" },
+	{ "Mac OS X ZFS",					"6A898CC3" "1DD2" "11B2" "99A6080020736631" },
+	{ "Mac OS X RAID",					"52414944" "0000" "11AA" "AA1100306543ECAC" },
+	{ "Mac OS X RAID, offline",			"52414944" "5F4F" "11AA" "AA1100306543ECAC" }, /* 30 */
+	{ "Mac OS X Boot",					"426F6F74" "0000" "11AA" "AA1100306543ECAC" },
+	{ "Mac OS X Label",					"4C616265" "6C00" "11AA" "AA1100306543ECAC" },
+	{ "Mac OS X TV Recovery",			"5265636F" "7665" "11AA" "AA1100306543ECAC" },
+	{ "Mac OS X Core Storage",			"53746F72" "6167" "11AA" "AA1100306543ECAC" },
+	{ "Solaris Boot",					"6A82CB45" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Root",					"6A85CF4D" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Swap",					"6A87C46F" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Backup",					"6A8B642B" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris /usr",					"6A898CC3" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris /var",					"6A8EF2E9" "1DD2" "11B2" "99A6080020736631" }, /* 40 */
+	{ "Solaris /home",					"6A90BA39" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Alternate sector",		"6A9283A5" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Reserved",				"6A945A3B" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Reserved",				"6A9630D1" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Reserved",				"6A980767" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Reserved",				"6A96237F" "1DD2" "11B2" "99A6080020736631" },
+	{ "Solaris Reserved",				"6A8D2AC7" "1DD2" "11B2" "99A6080020736631" },
+	{ "NetBSD Swap",					"49F48D32" "B10E" "11DC" "B99B0019D1879648" },
+	{ "NetBSD FFS",						"49F48D5A" "B10E" "11DC" "B99B0019D1879648" },
+	{ "NetBSD LFS",						"49F48D82" "B10E" "11DC" "B99B0019D1879648" }, /* 50 */
+	{ "NetBSD RAID",					"49F48DAA" "B10E" "11DC" "B99B0019D1879648" },
+	{ "NetBSD Concatenated",			"2DB519C4" "B10F" "11DC" "B99B0019D1879648" },
+	{ "NetBSD Encrypted",				"2DB519EC" "B10F" "11DC" "B99B0019D1879648" },
+	{ "ChromeOS ChromeOS kernel",		"FE3A2A5D" "4F32" "41A7" "B725ACCC3285A309" },
+	{ "ChromeOS rootfs",				"3CB8E202" "3B7E" "47DD" "8A3C7FF2A13CFCEC" },
+	{ "ChromeOS future use",			"2E0A753D" "9E48" "43B0" "8337B15192CB1B5E" },
+	{ "MidnightBSD Boot",				"85D5E45E" "237C" "11E1" "B4B3E89A8F7FC3A7" },
+	{ "MidnightBSD Data",				"85D5E45A" "237C" "11E1" "B4B3E89A8F7FC3A7" },
+	{ "MidnightBSD Swap",				"85D5E45B" "237C" "11E1" "B4B3E89A8F7FC3A7" },
+	{ "MidnightBSD UFS",				"0394Ef8B" "237E" "11E1" "B4B3E89A8F7FC3A7" }, /* 60 */
+	{ "MidnightBSD Vinum VM",			"85D5E45C" "237C" "11E1" "B4B3E89A8F7FC3A7" },
+	{ "MidnightBSD ZFS",				"85D5E45D" "237C" "11E1" "B4B3E89A8F7FC3A7" },
+	{ "Uknown", NULL} /* keep this as the last one! gpt_get_part_type depends on it! */
+};
+
+
+
Index: uspace/lib/gpt/gpt.h
===================================================================
--- uspace/lib/gpt/gpt.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/gpt/gpt.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libgpt
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBGPT_GPT_H_
+#define LIBGPT_GPT_H_
+
+typedef enum {
+	AT_REQ_PART = 0,
+	AT_NO_BLOCK_IO,
+	AT_LEGACY_BOOT,
+	AT_UNDEFINED,
+	AT_SPECIFIC = 48
+} GPT_ATTR;
+
+/** GPT header
+ * - all in little endian.
+ */
+typedef struct {
+	uint8_t  efi_signature[8];
+	uint8_t  revision[4];
+	uint32_t header_size;
+	uint32_t header_crc32;
+	uint32_t reserved;
+	uint64_t my_lba;
+	uint64_t alternate_lba;
+	uint64_t first_usable_lba;
+	uint64_t last_usable_lba;
+	uint8_t  disk_guid[16];
+	uint64_t entry_lba;
+	uint32_t fillries;
+	uint32_t entry_size;
+	uint32_t pe_array_crc32;
+} __attribute__((packed)) gpt_header_t;
+
+/** GPT partition entry */
+typedef struct {
+	uint8_t part_type[16];
+	uint8_t part_id[16];
+	uint64_t start_lba;
+	uint64_t end_lba;
+	uint64_t attributes;
+	uint8_t part_name[72];
+} __attribute__((packed)) gpt_entry_t;
+
+#endif
+
+
Index: uspace/lib/gpt/libgpt.c
===================================================================
--- uspace/lib/gpt/libgpt.c	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/gpt/libgpt.c	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,879 @@
+/*
+ * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libgpt
+ * @{
+ */
+/** @file
+ */
+
+/* TODO:
+ * This implementation only supports fixed size partition entries. Specification
+ * requires otherwise, though. Use void * array and casting to achieve that.
+ */
+
+#include <ipc/bd.h>
+#include <async.h>
+#include <stdio.h>
+#include <block.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <byteorder.h>
+#include <checksum.h>
+#include <mem.h>
+#include <sys/typefmt.h>
+#include <mbr.h>
+
+
+#include "libgpt.h"
+
+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 uint8_t get_byte(const char *);
+static bool check_overlap(gpt_part_t *, gpt_part_t *);
+static bool check_encaps(gpt_part_t *, uint64_t, uint64_t);
+
+/** Allocate memory for gpt label */
+gpt_label_t * gpt_alloc_label(void)
+{
+	gpt_label_t *label = malloc(sizeof(gpt_label_t));
+	if (label == NULL)
+		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->device = 0;
+	
+	return label;
+}
+
+/** Free gpt_label_t structure */
+void gpt_free_label(gpt_label_t *label)
+{
+	if (label->gpt != NULL)
+		gpt_free_gpt(label->gpt);
+	
+	if (label->parts != NULL)
+		gpt_free_partitions(label->parts);
+	
+	free(label);
+}
+
+/** Allocate memory for gpt header */
+gpt_t * gpt_alloc_header(size_t size)
+{
+	gpt_t *gpt = malloc(sizeof(gpt_t));
+	if (gpt == NULL)
+		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
+	 */
+	size_t final_size = size > sizeof(gpt_header_t) ? size : sizeof(gpt_header_t);
+	gpt->header = malloc(final_size);
+	if (gpt->header == NULL) {
+		free(gpt);
+		return NULL;
+	}
+	
+	/* Enter some sane defaults. */
+	memset(gpt->header, 0, final_size);
+	memcpy(gpt->header->efi_signature, efi_signature, 8);
+	memcpy(gpt->header->revision, revision, 4);
+	gpt->header->header_size = host2uint32_t_le(final_size);
+	gpt->header->entry_lba = host2uint64_t_le((uint64_t) 2);
+	gpt->header->entry_size = host2uint32_t_le(sizeof(gpt_entry_t));
+	
+	
+	return gpt;
+}
+
+/** free() GPT header including gpt->header_lba */
+void gpt_free_gpt(gpt_t *gpt)
+{
+	free(gpt->header);
+	free(gpt);
+}
+
+/** Read GPT from specific device
+ * @param label        label structure to fill
+ * @param dev_handle   device to read GPT from
+ *
+ * @return             EOK on success, errorcode on error
+ */
+int gpt_read_header(gpt_label_t *label, service_id_t dev_handle)
+{
+	int rc;
+	size_t b_size;
+	
+	rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK)
+		goto fail;
+	
+	rc = block_get_bsize(dev_handle, &b_size);
+	if (rc != EOK)
+		goto fini_fail;
+	
+	if (label->gpt == NULL) {
+		label->gpt = gpt_alloc_header(b_size);
+		if (label->gpt == NULL) {
+			rc = ENOMEM;
+			goto fini_fail;
+		}
+	}
+	
+	rc = load_and_check_header(dev_handle, GPT_HDR_BA, b_size, label->gpt->header);
+	if (rc == EBADCHECKSUM || rc == EINVAL) {
+		aoff64_t n_blocks;
+		rc = block_get_nblocks(dev_handle, &n_blocks);
+		if (rc != EOK)
+			goto free_fail;
+
+		rc = load_and_check_header(dev_handle, n_blocks - 1, b_size, label->gpt->header);
+		if (rc == EBADCHECKSUM || rc == EINVAL)
+			goto free_fail;
+	}
+	
+	label->device = dev_handle;
+	block_fini(dev_handle);
+	return EOK;
+	
+free_fail:
+	gpt_free_gpt(label->gpt);
+	label->gpt = NULL;
+fini_fail:
+	block_fini(dev_handle);
+fail:
+	return rc;
+}
+
+/** Write GPT header to device
+ * @param label        GPT label header to be written
+ * @param dev_handle   device handle to write the data to
+ *
+ * @return             EOK on success, libblock error code otherwise
+ *
+ * Note: Firstly write partitions (if modified), then gpt header.
+ */
+int gpt_write_header(gpt_label_t *label, service_id_t dev_handle)
+{
+	int rc;
+	size_t 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;
+	
+	aoff64_t n_blocks;
+	rc = block_get_nblocks(dev_handle, &n_blocks);
+	if (rc != EOK) {
+		block_fini(dev_handle);
+		return rc;
+	}
+	
+	uint64_t tmp;
+	
+	gpt_set_random_uuid(label->gpt->header->disk_guid);
+	
+	/* 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 */
+	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);
+	if (rc != EOK)
+		return rc;
+	
+	/* Write Protective MBR */
+	br_block_t mbr;
+	memset(&mbr, 0, 512);
+	memset(mbr.pte[0].first_chs, 1, 3);
+	mbr.pte[0].ptype = 0xEE;
+	memset(mbr.pte[0].last_chs, 0xFF, 3);
+	mbr.pte[0].first_lba = host2uint32_t_le(1);
+	mbr.pte[0].length = 0xFFFFFFFF;
+	mbr.signature = host2uint16_t_le(BR_SIGNATURE);
+	
+	rc = block_write_direct(dev_handle, 0, 1, &mbr);
+	block_fini(dev_handle);
+	if (rc != EOK)
+		return rc;
+	
+	return 0;
+}
+
+/** Alloc partition array */
+gpt_partitions_t * gpt_alloc_partitions()
+{
+	return alloc_part_array(GPT_MIN_PART_NUM);
+}
+
+/** Parse partitions from GPT
+ * @param label   GPT label to be parsed
+ *
+ * @return        EOK on success, errorcode otherwise
+ */
+int gpt_read_partitions(gpt_label_t *label)
+{
+	int rc;
+	unsigned int i;
+	uint32_t fillries = uint32_t_le2host(label->gpt->header->fillries);
+	uint32_t ent_size = uint32_t_le2host(label->gpt->header->entry_size);
+	uint64_t ent_lba = uint64_t_le2host(label->gpt->header->entry_lba);
+	
+	if (label->parts == NULL) {
+		label->parts = alloc_part_array(fillries);
+		if (label->parts == NULL) {
+			return ENOMEM;
+		}
+	}
+
+	/* comm_size is ignored */
+	rc = block_init(EXCHANGE_SERIALIZE, label->device, sizeof(gpt_entry_t));
+	if (rc != EOK)
+		goto fail;
+
+	size_t block_size;
+	rc = block_get_bsize(label->device, &block_size);
+	if (rc != EOK)
+		goto fini_fail;
+
+	aoff64_t pos = ent_lba * block_size;
+
+	/* 
+	 * 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) 
+	 */
+	for (i = 0; i < fillries; ++i) {
+		/*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));
+		 */
+		pos += ent_size;
+
+		if (rc != EOK)
+			goto fini_fail;
+	}
+	
+	uint32_t crc = compute_crc32((uint8_t *) label->parts->part_array, 
+	                   fillries * ent_size);
+
+	if (uint32_t_le2host(label->gpt->header->pe_array_crc32) != crc)
+	{
+		rc = EBADCHECKSUM;
+		goto fini_fail;
+	}
+	
+	block_fini(label->device);
+	return EOK;
+	
+fini_fail:
+	block_fini(label->device);
+	
+fail:
+	gpt_free_partitions(label->parts);
+	label->parts = NULL;
+	return rc;
+}
+
+/** Write GPT and partitions to device
+ * Note: also writes the header.
+ * @param label        label to write
+ * @param dev_handle   device to write the data to
+ *
+ * @return             returns EOK on succes, errorcode otherwise
+ */
+int gpt_write_partitions(gpt_label_t *label, service_id_t dev_handle)
+{
+	int rc;
+	size_t b_size;
+	
+	/* comm_size of 4096 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)
+		goto fail;
+	
+	aoff64_t n_blocks;
+	rc = block_get_nblocks(dev_handle, &n_blocks);
+	if (rc != EOK)
+		goto fail;
+	
+	/* When we're creating a new label from scratch, we need to fill 
+	 * the header with sensible defaults. */
+	if (label->gpt == NULL) {
+		label->gpt = gpt_alloc_header(b_size);
+	}
+	
+	uint32_t e_size = uint32_t_le2host(label->gpt->header->entry_size);
+	size_t fillries = label->parts->fill > GPT_MIN_PART_NUM ? label->parts->fill : GPT_MIN_PART_NUM;
+	
+	if (e_size != sizeof(gpt_entry_t))
+		return ENOTSUP;
+
+	label->gpt->header->fillries = host2uint32_t_le(fillries);
+	uint64_t arr_blocks = (fillries * sizeof(gpt_entry_t)) / b_size;
+	uint64_t gpt_space = arr_blocks + GPT_HDR_BS + 1; /* +1 for Protective MBR */
+	label->gpt->header->first_usable_lba = host2uint64_t_le(gpt_space);
+	label->gpt->header->last_usable_lba = host2uint64_t_le(n_blocks - gpt_space - 1);
+	
+	/* Perform checks */
+	gpt_part_foreach (label, p) {
+		if (gpt_get_part_type(p) == GPT_PTE_UNUSED)
+			continue;
+		
+		if (!check_encaps(p, n_blocks, gpt_space)) {
+			rc = ERANGE;
+			goto fail;
+		}
+		
+		gpt_part_foreach (label, q) {
+			if (p == q)
+				continue;
+			
+			if (gpt_get_part_type(p) != GPT_PTE_UNUSED) {
+				if (check_overlap(p, q)) {
+					rc = ERANGE;
+					goto fail;
+				}
+			}
+		}
+	}
+	
+	label->gpt->header->pe_array_crc32 = host2uint32_t_le(compute_crc32(
+	                               (uint8_t *) label->parts->part_array,
+	                               fillries * e_size));
+	
+	
+	/* Write to backup GPT partition array location */
+	rc = block_write_direct(dev_handle, n_blocks - arr_blocks - 1, 
+	         arr_blocks, label->parts->part_array);
+	if (rc != EOK)
+		goto fail;
+	
+	/* Write to main GPT partition array location */
+	rc = block_write_direct(dev_handle, uint64_t_le2host(label->gpt->header->entry_lba),
+	         arr_blocks, label->parts->part_array);
+	if (rc != EOK)
+		goto fail;
+	
+	return gpt_write_header(label, dev_handle);
+	
+fail:
+	block_fini(dev_handle);
+	return rc;
+}
+
+/** Alloc new partition
+ *
+ * @return        returns pointer to the new partition or NULL
+ *
+ * Note: use either gpt_alloc_partition or gpt_get_partition.
+ * This returns a memory block (zero-filled) and needs gpt_add_partition()
+ * to be called to insert it into a partition array.
+ * Requires you to call gpt_free_partition afterwards.
+ */
+gpt_part_t * gpt_alloc_partition(void)
+{
+	gpt_part_t *p = malloc(sizeof(gpt_part_t));
+	if (p == NULL)
+		return NULL;
+	
+	memset(p, 0, sizeof(gpt_part_t));
+	
+	return p;
+}
+
+/** Alloc new partition already inside the label
+ *
+ * @param label   label to carry new partition
+ *
+ * @return        returns pointer to the new partition or NULL on ENOMEM
+ *
+ * Note: use either gpt_alloc_partition or gpt_get_partition.
+ * This one returns a pointer to the first empty structure already
+ * inside the array, so don't call gpt_add_partition() afterwards.
+ * This is the one you will usually want.
+ */
+gpt_part_t * gpt_get_partition(gpt_label_t *label)
+{
+	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 NULL;
+		}
+		
+		p = label->parts->part_array + label->parts->fill++;
+		
+	} while (gpt_get_part_type(p) != GPT_PTE_UNUSED);
+	
+	return p;
+}
+
+/** Get partition already inside the label
+ *
+ * @param label   label to carrying the partition
+ * @param idx     index of the partition
+ *
+ * @return        returns pointer to the partition
+ *                or NULL when out of range
+ *
+ * Note: For new partitions use either gpt_alloc_partition or
+ * gpt_get_partition unless you want a partition at a specific place.
+ * This returns a pointer to a structure already inside the array,
+ * so don't call gpt_add_partition() afterwards.
+ * This function is handy when you want to change already existing
+ * partition or to simply write somewhere in the middle. This works only
+ * for indexes smaller than either 128 or the actual number of filled
+ * entries.
+ */
+gpt_part_t * gpt_get_partition_at(gpt_label_t *label, size_t idx)
+{
+	return NULL;
+	
+	if (idx >= GPT_MIN_PART_NUM && idx >= label->parts->fill)
+		return NULL;
+	
+	return label->parts->part_array + idx;
+}
+
+/** Copy partition into partition array
+ *
+ * @param parts			target label
+ * @param partition		source partition to copy
+ *
+ * @return 				-1 on error, 0 otherwise
+ *
+ * Note: for use with gpt_alloc_partition() only. You will get
+ * duplicates with gpt_get_partition().
+ * Note: does not call gpt_free_partition()!
+ */
+int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
+{
+	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));
+	
+	
+	return EOK;
+}
+
+/** Remove partition from array
+ * @param label   label to remove from
+ * @param idx     index of the partition to remove
+ *
+ * @return        EOK on success, ENOMEM on array reduction failure
+ *
+ * Note: even if it fails, the partition still gets removed. Only
+ * reducing the array failed.
+ */
+int gpt_remove_partition(gpt_label_t *label, size_t idx)
+{
+	if (idx >= label->parts->arr_size)
+		return EINVAL;
+	
+	/* 
+	 * 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.
+	 */
+	memset(label->parts->part_array + idx, 0, sizeof(gpt_entry_t));
+	
+	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. 
+	 */
+	gpt_part_t * p;
+	
+	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) {
+				if (gpt_get_part_type(p) != GPT_PTE_UNUSED)
+					return EOK;
+		}
+		
+		if (reduce_part_array(label->parts) == ENOMEM)
+			return ENOMEM;
+	}
+
+	return EOK;
+}
+
+/** Free partition list
+ *
+ * @param parts		partition list to be freed
+ */
+void gpt_free_partitions(gpt_partitions_t * parts)
+{
+	free(parts->part_array);
+	free(parts);
+}
+
+/** Get partition type by linear search
+ * (hopefully this doesn't get slow)
+ */
+size_t gpt_get_part_type(gpt_part_t * p)
+{
+	size_t i;
+	
+	for (i = 0; gpt_ptypes[i].guid != NULL; i++) {
+		if (p->part_type[3] == get_byte(gpt_ptypes[i].guid +0) &&
+			p->part_type[2] == get_byte(gpt_ptypes[i].guid +2) &&
+			p->part_type[1] == get_byte(gpt_ptypes[i].guid +4) &&
+			p->part_type[0] == get_byte(gpt_ptypes[i].guid +6) &&
+			
+			p->part_type[5] == get_byte(gpt_ptypes[i].guid +8) &&
+			p->part_type[4] == get_byte(gpt_ptypes[i].guid +10) &&
+			
+			p->part_type[7] == get_byte(gpt_ptypes[i].guid +12) &&
+			p->part_type[6] == get_byte(gpt_ptypes[i].guid +14) &&
+			
+			p->part_type[8] == get_byte(gpt_ptypes[i].guid +16) &&
+			p->part_type[9] == get_byte(gpt_ptypes[i].guid +18) &&
+			p->part_type[10] == get_byte(gpt_ptypes[i].guid +20) &&
+			p->part_type[11] == get_byte(gpt_ptypes[i].guid +22) &&
+			p->part_type[12] == get_byte(gpt_ptypes[i].guid +24) &&
+			p->part_type[13] == get_byte(gpt_ptypes[i].guid +26) &&
+			p->part_type[14] == get_byte(gpt_ptypes[i].guid +28) &&
+			p->part_type[15] == get_byte(gpt_ptypes[i].guid +30))
+				break;
+	}
+	
+	return i;
+}
+
+/** Set partition type
+ * @param p			partition to be set
+ * @param type		partition type to set
+ * 					- see our fine selection at gpt_ptypes to choose from
+ */
+void gpt_set_part_type(gpt_part_t * p, size_t type)
+{
+	/* Beware: first 3 blocks are byteswapped! */
+	p->part_type[3] = get_byte(gpt_ptypes[type].guid +0);
+	p->part_type[2] = get_byte(gpt_ptypes[type].guid +2);
+	p->part_type[1] = get_byte(gpt_ptypes[type].guid +4);
+	p->part_type[0] = get_byte(gpt_ptypes[type].guid +6);
+	                
+	p->part_type[5] = get_byte(gpt_ptypes[type].guid +8);
+	p->part_type[4] = get_byte(gpt_ptypes[type].guid +10);
+	                
+	p->part_type[7] = get_byte(gpt_ptypes[type].guid +12);
+	p->part_type[6] = get_byte(gpt_ptypes[type].guid +14);
+	                
+	p->part_type[8] = get_byte(gpt_ptypes[type].guid +16);
+	p->part_type[9] = get_byte(gpt_ptypes[type].guid +18);
+	p->part_type[10] = get_byte(gpt_ptypes[type].guid +20);
+	p->part_type[11] = get_byte(gpt_ptypes[type].guid +22);
+	p->part_type[12] = get_byte(gpt_ptypes[type].guid +24);
+	p->part_type[13] = get_byte(gpt_ptypes[type].guid +26);
+	p->part_type[14] = get_byte(gpt_ptypes[type].guid +28);
+	p->part_type[15] = get_byte(gpt_ptypes[type].guid +30);
+}
+
+/** Get partition starting LBA */
+uint64_t gpt_get_start_lba(gpt_part_t * p)
+{
+	return uint64_t_le2host(p->start_lba);
+}
+
+/** Set partition starting LBA */
+void gpt_set_start_lba(gpt_part_t * p, uint64_t start)
+{
+	p->start_lba = host2uint64_t_le(start);
+}
+
+/** Get partition ending LBA */
+uint64_t gpt_get_end_lba(gpt_part_t * p)
+{
+	return uint64_t_le2host(p->end_lba);
+}
+
+/** Set partition ending LBA */
+void gpt_set_end_lba(gpt_part_t * p, uint64_t end)
+{
+	p->end_lba = host2uint64_t_le(end);
+}
+
+/** Get partition name */
+unsigned char * gpt_get_part_name(gpt_part_t * p)
+{
+	return p->part_name;
+}
+
+/** Copy partition name */
+void gpt_set_part_name(gpt_part_t *p, char *name, size_t length)
+{
+	if (length >= 72)
+		length = 71;
+
+	memcpy(p->part_name, name, length);
+	p->part_name[length] = '\0';
+}
+
+/** Get partition attribute */
+bool gpt_get_flag(gpt_part_t * p, GPT_ATTR flag)
+{
+	return (p->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
+}
+
+/** Set partition attribute */
+void gpt_set_flag(gpt_part_t * p, GPT_ATTR flag, bool value)
+{
+	uint64_t attr = p->attributes;
+
+	if (value)
+		attr = attr | (((uint64_t) 1) << flag);
+	else
+		attr = attr ^ (attr & (((uint64_t) 1) << flag));
+
+	p->attributes = attr;
+}
+
+/** Generate a new pseudo-random UUID
+ * @param uuid Pointer to the UUID to overwrite.
+ */
+void gpt_set_random_uuid(uint8_t * uuid)
+{
+	srandom((unsigned int) (size_t) uuid);
+	
+	unsigned int i;
+	for (i = 0; i < 16/sizeof(long int); ++i)
+		((long int *)uuid)[i] = random();
+	
+}
+
+/** 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)
+{
+	int rc;
+
+	rc = block_read_direct(dev_handle, addr, GPT_HDR_BS, header);
+	if (rc != EOK)
+		return rc;
+
+	unsigned int i;
+	/* Check the EFI signature */
+	for (i = 0; i < 8; ++i) {
+		if (header->efi_signature[i] != efi_signature[i])
+			return EINVAL;
+	}
+
+	/* Check the CRC32 of the header */
+	uint32_t crc = header->header_crc32;
+	header->header_crc32 = 0;
+	if (crc != compute_crc32((uint8_t *) header, header->header_size))
+		return EBADCHECKSUM;
+	else
+		header->header_crc32 = crc;
+
+	/* Check for zeroes in the rest of the block */
+	for (i = sizeof(gpt_header_t); i < b_size; ++i) {
+		if (((uint8_t *) header)[i] != 0)
+			return EINVAL;
+	}
+
+	return EOK;
+}
+
+static gpt_partitions_t * alloc_part_array(uint32_t num)
+{
+	gpt_partitions_t * res = malloc(sizeof(gpt_partitions_t));
+	if (res == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
+	res->part_array = malloc(size * sizeof(gpt_entry_t));
+	if (res->part_array == NULL) {
+		free(res);
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	memset(res->part_array, 0, size * sizeof(gpt_entry_t));
+	
+	res->fill = 0;
+	res->arr_size = num;
+
+	return res;
+}
+
+static int extend_part_array(gpt_partitions_t * p)
+{
+	size_t nsize = p->arr_size * 2;
+	gpt_entry_t * tmp = malloc(nsize * sizeof(gpt_entry_t));
+	if (tmp == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	
+	memcpy(tmp, p->part_array, p->fill * sizeof(gpt_entry_t));
+	free(p->part_array);
+	p->part_array = tmp;
+	p->arr_size = nsize;
+
+	return 0;
+}
+
+static int reduce_part_array(gpt_partitions_t * p)
+{
+	if (p->arr_size > GPT_MIN_PART_NUM) {
+		unsigned int nsize = p->arr_size / 2;
+		nsize = nsize > GPT_MIN_PART_NUM ? nsize : GPT_MIN_PART_NUM;
+		gpt_entry_t * tmp = malloc(nsize * sizeof(gpt_entry_t));
+		if (tmp == NULL)
+			return ENOMEM;
+
+		memcpy(tmp, p->part_array, p->fill < nsize ? p->fill : nsize);
+		free(p->part_array);
+		p->part_array = tmp;
+		p->arr_size = nsize;
+	}
+
+	return 0;
+}
+
+/* Parse a byte from a string in hexadecimal 
+ * i.e., "FF" => 255 
+ */
+static uint8_t get_byte(const char * c)
+{
+	uint8_t val = 0;
+	char hex[3] = {*c, *(c+1), 0};
+	
+	errno = str_uint8_t(hex, NULL, 16, false, &val);
+	return val;
+}
+
+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 false;
+	} else if (gpt_get_start_lba(p1) > gpt_get_start_lba(p2) && gpt_get_end_lba(p2) < gpt_get_start_lba(p1)) {
+		return false;
+	}
+
+	return true;
+}
+
+static bool check_encaps(gpt_part_t *p, uint64_t n_blocks, uint64_t first_lba)
+{
+	/* 
+	 * We allow "<=" in the second expression because it lacks MBR so 
+	 * it's by 1 block smaller.
+	 */
+	if (gpt_get_start_lba(p) >= first_lba && gpt_get_end_lba(p) <= n_blocks - first_lba)
+		return true;
+	
+	return false;
+}
Index: uspace/lib/gpt/libgpt.h
===================================================================
--- uspace/lib/gpt/libgpt.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/gpt/libgpt.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libgpt
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBGPT_LIBGPT_H_
+#define LIBGPT_LIBGPT_H_
+
+#define LIBGPT_NAME	"libgpt"
+
+#include <loc.h>
+#include <sys/types.h>
+
+#include "gpt.h"
+
+/** Block address of GPT header. */
+#define GPT_HDR_BA	1
+/** Block size of GPT header. */
+#define GPT_HDR_BS	1
+/** Minimum number of GPT partition entries */
+#define GPT_MIN_PART_NUM 128
+/** Basic number of GPT partition entries */
+#define GPT_BASE_PART_NUM (GPT_MIN_PART_NUM)
+/** How much fill we ignore before resizing partition array */
+#define GPT_IGNORE_FILL_NUM 10
+
+/** Unused partition entry */
+#define GPT_PTE_UNUSED 0
+
+/** GPT header signature ("EFI PART" in ASCII) */
+extern const uint8_t efi_signature[8];
+extern const uint8_t revision[4];
+
+typedef struct {
+	/** Raw header. Has more bytes alloced than sizeof(gpt_header_t)!
+	 * See gpt_alloc_header() to know why. */
+	gpt_header_t *header;
+} gpt_t;
+
+typedef gpt_entry_t gpt_part_t;
+
+typedef struct gpt_parts {
+	/** Number of entries */
+	size_t fill;
+	/** Size of the array */
+	size_t arr_size;
+	/** Resizable partition array */
+	gpt_entry_t *part_array;
+} gpt_partitions_t;
+
+
+typedef struct gpt_table {
+	gpt_t *gpt;
+	gpt_partitions_t *parts;
+	service_id_t device;
+} gpt_label_t;
+
+struct partition_type {
+	const char *desc;
+	const char *guid;
+};
+
+extern const struct partition_type gpt_ptypes[];
+
+extern gpt_label_t * gpt_alloc_label(void);
+extern void gpt_free_label(gpt_label_t *);
+
+extern gpt_t * gpt_alloc_header(size_t);
+extern int     gpt_read_header(gpt_label_t *, service_id_t);
+extern int     gpt_write_header(gpt_label_t *, service_id_t);
+
+extern gpt_partitions_t * gpt_alloc_partitions(void);
+extern int             gpt_read_partitions (gpt_label_t *);
+extern int             gpt_write_partitions(gpt_label_t *, service_id_t);
+extern gpt_part_t *    gpt_alloc_partition (void);
+extern gpt_part_t *    gpt_get_partition   (gpt_label_t *);
+extern gpt_part_t *    gpt_get_partition_at(gpt_label_t *, size_t);
+extern int             gpt_add_partition   (gpt_label_t *, gpt_part_t *);
+extern int             gpt_remove_partition(gpt_label_t *, size_t);
+
+extern size_t          gpt_get_part_type(gpt_part_t *);
+extern void            gpt_set_part_type(gpt_part_t *, size_t);
+extern void            gpt_set_start_lba(gpt_part_t *, uint64_t);
+extern uint64_t        gpt_get_start_lba(gpt_part_t *);
+extern void            gpt_set_end_lba  (gpt_part_t *, uint64_t);
+extern uint64_t        gpt_get_end_lba  (gpt_part_t *);
+extern unsigned char * gpt_get_part_name(gpt_part_t *);
+extern void            gpt_set_part_name(gpt_part_t *, char *, size_t);
+extern bool            gpt_get_flag     (gpt_part_t *, GPT_ATTR);
+extern void            gpt_set_flag     (gpt_part_t *, GPT_ATTR, bool);
+
+extern void            gpt_set_random_uuid(uint8_t *);
+extern uint64_t        gpt_get_next_aligned(uint64_t, unsigned int);
+
+
+#define gpt_part_foreach(label, iterator) \
+		for(gpt_part_t * iterator = (label)->parts->part_array; \
+		    iterator < (label)->parts->part_array + (label)->parts->arr_size; ++iterator)
+
+extern void gpt_free_gpt(gpt_t *);
+extern void gpt_free_partitions(gpt_partitions_t *);
+
+#endif
+
Index: uspace/lib/mbr/Makefile
===================================================================
--- uspace/lib/mbr/Makefile	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/mbr/Makefile	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2011 Dominik Taborsky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -DDEBUG_CONFIG
+LIBRARY = libmbr
+
+SOURCES = \
+	libmbr.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/mbr/libmbr.c
===================================================================
--- uspace/lib/mbr/libmbr.c	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/mbr/libmbr.c	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The LIBMBR_NAME of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /** @addtogroup libmbr
+ * @{
+ */
+/** @file MBR extraxtion library
+ */
+
+#include <async.h>
+#include <assert.h>
+#include <block.h>
+#include <byteorder.h>
+#include <errno.h>
+#include <ipc/bd.h>
+#include <mem.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str_error.h>
+
+#include "libmbr.h"
+
+static br_block_t * alloc_br(void);
+static int decode_part(pt_entry_t *, mbr_part_t *, uint32_t);
+static int decode_logical(mbr_label_t *, mbr_part_t *);
+static void encode_part(mbr_part_t *, pt_entry_t *, uint32_t, bool);
+static bool check_overlap(mbr_part_t *, mbr_part_t *);
+static bool check_encaps(mbr_part_t *, mbr_part_t *);
+static bool check_preceeds(mbr_part_t *, mbr_part_t *);
+static mbr_err_val mbr_add_primary(mbr_label_t *, mbr_part_t *);
+static mbr_err_val mbr_add_logical(mbr_label_t *, mbr_part_t *);
+
+/** Allocate and initialize mbr_label_t structure */
+mbr_label_t * mbr_alloc_label(void)
+{
+	mbr_label_t *label = malloc(sizeof(mbr_label_t));
+	if (label == NULL)
+		return NULL;
+	
+	label->mbr = NULL;
+	label->parts = NULL;
+	label->device = 0;
+	
+	return label;
+}
+
+void mbr_set_device(mbr_label_t *label, service_id_t dev_handle)
+{
+	label->device = dev_handle;
+}
+
+/** Free mbr_label_t structure */
+void mbr_free_label(mbr_label_t *label)
+{
+	if (label->mbr != NULL)
+		mbr_free_mbr(label->mbr);
+	
+	if (label->parts != NULL)
+		mbr_free_partitions(label->parts);
+	
+	free(label);
+}
+
+/** Allocate memory for mbr_t */
+mbr_t * mbr_alloc_mbr(void)
+{
+	return malloc(sizeof(mbr_t));
+}
+
+/** Read MBR from specific device
+ * @param   label       label to write data to
+ * @param   dev_handle  device to read MBR from
+ *
+ * @return				EOK on success, error code on error
+ */
+int mbr_read_mbr(mbr_label_t *label, service_id_t dev_handle)
+{	
+	int rc;
+	
+	if (label->mbr == NULL) {
+		label->mbr = mbr_alloc_mbr();
+		if (label->mbr == NULL) {
+			return ENOMEM;
+		}
+	}
+
+	rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK)
+		return rc;
+
+	rc = block_read_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
+	block_fini(dev_handle);
+	if (rc != EOK)
+		return rc;
+
+	label->device = dev_handle;
+
+	return EOK;
+}
+
+/** Write mbr to disk
+ * @param label			MBR to be written
+ * @param dev_handle	device handle to write MBR to (may be different
+ * 							from the device in 'mbr')
+ *
+ * @return				0 on success, otherwise libblock error code
+ */
+int mbr_write_mbr(mbr_label_t *label, service_id_t dev_handle)
+{
+	int rc;
+
+	rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = block_write_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
+	block_fini(dev_handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Decide whether this is an actual MBR or a Protective MBR from GPT
+ *
+ * @param mbr		the actual MBR to decide upon
+ *
+ * @return			1 if MBR, 0 if GPT
+ */
+int mbr_is_mbr(mbr_label_t *label)
+{
+	return (label->mbr->raw_data.pte[0].ptype != PT_GPT) ? 1 : 0;
+}
+
+/** Parse partitions from MBR, freeing previous partitions if any
+ * NOTE: it is assumed mbr_read_mbr(label) was called before.
+ * @param label  MBR to be parsed
+ *
+ * @return       linked list of partitions or NULL on error
+ */
+int mbr_read_partitions(mbr_label_t *label)
+{
+	if (label == NULL || label->mbr == NULL)
+		return EINVAL;
+	
+	int rc, rc_ext;
+	unsigned int i;
+	mbr_part_t *p;
+	mbr_part_t *ext = NULL;
+	
+	if (label->parts != NULL)
+		mbr_free_partitions(label->parts);
+	
+	label->parts = mbr_alloc_partitions();
+	if (label->parts == NULL) {
+		return ENOMEM;
+	}
+	
+	/* Generate the primary partitions */
+	for (i = 0; i < N_PRIMARY; ++i) {
+		if (label->mbr->raw_data.pte[i].ptype == PT_UNUSED)
+			continue;
+		
+		p = mbr_alloc_partition();
+		if (p == NULL) {
+			printf(LIBMBR_NAME ": Error on memory allocation.\n");
+			mbr_free_partitions(label->parts);
+			return ENOMEM;
+		}
+		
+		rc_ext = decode_part(&(label->mbr->raw_data.pte[i]), p, 0);
+		mbr_set_flag(p, ST_LOGIC, false);
+		rc = mbr_add_partition(label, p);
+		if (rc != ERR_OK) {
+			printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
+			       LIBMBR_NAME ": MBR is invalid.\n", rc);
+			mbr_free_partitions(label->parts);
+			return EINVAL;
+		}
+		
+		if (rc_ext) {
+			ext = p;
+			label->parts->l_extended = &p->link;
+		}
+	}
+	
+	/* Fill in the primary partitions and generate logical ones, if any */
+	rc = decode_logical(label, ext);
+	if (rc != EOK) {
+		printf(LIBMBR_NAME ": Error during decoding logical partitions: %d - %s.\n" \
+			   LIBMBR_NAME ": Partition list may be incomplete.\n", rc, str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/** Write MBR and partitions to device
+ * @param label        label to write
+ * @param dev_handle   device to write the data to
+ *
+ * @return             returns EOK on succes, specific error code otherwise
+ */
+int mbr_write_partitions(mbr_label_t *label, service_id_t dev_handle)
+{
+	if (label->parts == NULL)
+		return EOK;
+	
+	if (label->mbr == NULL)
+		label->mbr = mbr_alloc_mbr();
+	
+	int i = 0;
+	int rc;
+	mbr_part_t *p;
+	mbr_part_t *ext = (label->parts->l_extended == NULL) ? NULL
+					: list_get_instance(label->parts->l_extended, mbr_part_t, link);
+	
+	rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK) {
+		printf(LIBMBR_NAME ": Error while initializing libblock: %d - %s.\n", rc, str_error(rc));
+		return rc;
+	}
+	
+	link_t *l = label->parts->list.head.next;
+	
+	/* Encoding primary partitions */
+	for (i = 0; i < N_PRIMARY; i++) {
+		p = list_get_instance(l, mbr_part_t, link);	
+		encode_part(p, &(label->mbr->raw_data.pte[i]), 0, false);
+		l = l->next;
+	}
+	
+	label->mbr->raw_data.signature = host2uint16_t_le(BR_SIGNATURE);
+	
+	/* Writing MBR */
+	rc = block_write_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
+	if (rc != EOK) {
+		printf(LIBMBR_NAME ": Error while writing MBR : %d - %s.\n", rc, str_error(rc));
+		goto end;
+	}
+	
+	if (ext == NULL) {
+		rc = EOK;
+		goto end;
+	}
+	
+	uint32_t base = ext->start_addr;
+	mbr_part_t *prev_p;
+	
+	/* Note for future changes: Some thought has been put into design
+	 * and implementation. If you don't have to change it, don't. Other
+	 * designs have been tried, this came out as the least horror with
+	 * as much power over it as you can get. */
+	
+	/* Encoding and writing first logical partition */
+	if (l != &(label->parts->list.head)) {
+		p = list_get_instance(l, mbr_part_t, link);
+		p->ebr_addr = base;
+		encode_part(p, &(p->ebr->pte[0]), base, false);
+		l = l->next;
+	} else {
+		/* If there was an extended but no logical, we should overwrite
+		 * the space where the first logical's EBR would have been. There
+		 * might be some garbage from the past. */
+		br_block_t * tmp = alloc_br();
+		rc = block_write_direct(dev_handle, base, 1, tmp);
+		if (rc != EOK) {
+			printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
+			goto end;
+		}
+		free(tmp);
+		rc = EOK;
+		goto end;
+	}
+	
+	prev_p = p;
+	
+	/* Check EBR addresses
+	 * This piece of code saves previous EBR placements from other
+	 * software. But if our user modifies the logical partition chain,
+	 * we have to fix those placements if needed.*/
+	link_t *l_ebr = l;
+	link_t *l_iter;
+	mbr_part_t *tmp = mbr_alloc_partition();
+	tmp->length = 1;
+	while (l_ebr != &(label->parts->list.head)) {
+		p = list_get_instance(l_ebr, mbr_part_t, link);
+		tmp->start_addr = p->ebr_addr;
+		
+		l_iter = l;
+		while (l_iter != &(label->parts->list.head)) {
+			/* Checking whether EBR address makes sense. If not, we take a guess.
+			 * So far this is simple, we just take the first preceeding sector.
+			 * Fdisk always reserves at least 2048 sectors (1MiB), so it can have 
+			 * the EBR aligned as well as the partition itself. Parted reserves
+			 * minimum one sector, like we do.
+			 * 
+			 * Note that we know there is at least one sector free from previous checks.
+			 * Also note that the user can set ebr_addr to their liking (if it's valid). */		 
+			if (p->ebr_addr < base || p->ebr_addr >= base + ext->length ||
+			  check_overlap(tmp, list_get_instance(l_iter, mbr_part_t, link))) {
+				p->ebr_addr = p->start_addr - 1;
+				break;
+			}
+			
+			l_iter = l_iter->next;
+		}
+		
+		l_ebr = l_ebr->next;
+	}
+	mbr_free_partition(tmp);
+	
+	/* Encoding and writing logical partitions */
+	while (l != &(label->parts->list.head)) {
+		p = list_get_instance(l, mbr_part_t, link);
+		
+		
+		encode_part(p, &(p->ebr->pte[0]), p->ebr_addr, false);
+		encode_part(p, &(prev_p->ebr->pte[1]), base, true);
+		
+		rc = block_write_direct(dev_handle, prev_p->ebr_addr, 1, prev_p->ebr);
+		if (rc != EOK) {
+			printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
+			goto end;
+		}
+		
+		prev_p = p;
+		l = l->next;
+	}
+	
+	/* write the last EBR */
+	encode_part(NULL, &(prev_p->ebr->pte[1]), 0, false);
+	rc = block_write_direct(dev_handle, prev_p->ebr_addr, 1, prev_p->ebr);
+	if (rc != EOK) {
+		printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
+		goto end;
+	}
+	
+	rc = EOK;
+	
+end:
+	block_fini(dev_handle);
+	
+	return rc;
+}
+
+/** mbr_part_t constructor */
+mbr_part_t * mbr_alloc_partition(void)
+{
+	mbr_part_t *p = malloc(sizeof(mbr_part_t));
+	if (p == NULL) {
+		return NULL;
+	}
+	
+	link_initialize(&(p->link));
+	p->ebr = NULL;
+	p->type = PT_UNUSED;
+	p->status = 0;
+	p->start_addr = 0;
+	p->length = 0;
+	p->ebr_addr = 0;
+	
+	return p;
+}
+
+/** mbr_partitions_t constructor */
+mbr_partitions_t * mbr_alloc_partitions(void)
+{
+	mbr_partitions_t *parts = malloc(sizeof(mbr_partitions_t));
+	if (parts == NULL) {
+		return NULL;
+	}
+	
+	list_initialize(&(parts->list));
+	parts->n_primary = 0;
+	parts->n_logical = 0;
+	parts->l_extended = NULL;
+	
+	/* add blank primary partitions */
+	int i;
+	mbr_part_t *p;
+	for (i = 0; i < N_PRIMARY; ++i) {
+		p = mbr_alloc_partition();
+		if (p == NULL) {
+			mbr_free_partitions(parts);
+			return NULL;
+		}
+		list_append(&(p->link), &(parts->list));
+	}
+	
+
+	return parts;
+}
+
+/** Add partition
+ * 	Performs checks, sorts the list.
+ * 
+ * @param label			label to add to
+ * @param p				partition to add
+ * 
+ * @return				ERR_OK (0) on success, other MBR_ERR_VAL otherwise
+ */
+mbr_err_val mbr_add_partition(mbr_label_t *label, mbr_part_t *p)
+{
+	int rc1, rc2;
+	aoff64_t nblocks;
+	
+	rc1 = block_init(EXCHANGE_ATOMIC, label->device, 512);
+	if (rc1 != EOK && rc1 != EEXIST) {
+		printf(LIBMBR_NAME ": Error during libblock init: %d - %s.\n", rc1, str_error(rc1));
+		return ERR_LIBBLOCK;
+	}
+	
+	rc2 = block_get_nblocks(label->device, &nblocks);
+	
+	if (rc1 != EEXIST)
+		block_fini(label->device);
+	
+	if (rc2 != EOK) {
+		printf(LIBMBR_NAME ": Error while getting number of blocks: %d - %s.\n", rc2, str_error(rc2));
+		return ERR_LIBBLOCK;
+	}
+	
+	if ((aoff64_t) p->start_addr + p->length > nblocks)
+		return ERR_OUT_BOUNDS;
+	
+	if (label->parts == NULL) {
+		label->parts = mbr_alloc_partitions();
+		if (label->parts == NULL)
+			return ENOMEM; //FIXME! merge mbr_err_val into errno.h
+	}
+	
+	if (mbr_get_flag(p, ST_LOGIC))
+		/* adding logical partition */
+		return mbr_add_logical(label, p);
+	else
+		/* adding primary */
+		return mbr_add_primary(label, p);
+}
+
+/** Remove partition
+ * 	Removes partition by index, indexed from zero. When removing extended
+ *  partition, all logical partitions get removed as well.
+ * 
+ * @param label			label to remove from
+ * @param idx			index of the partition to remove
+ * 
+ * @return				EOK on success, EINVAL if idx invalid
+ */
+int mbr_remove_partition(mbr_label_t *label, size_t idx)
+{
+	link_t *l = list_nth(&(label->parts->list), idx);
+	if (l == NULL)
+		return EINVAL;
+	
+	mbr_part_t *p;
+	
+	/* If we're removing an extended partition, remove all logical as well */
+	if (l == label->parts->l_extended) {
+		label->parts->l_extended = NULL;
+		
+		link_t *it = l->next;
+		link_t *next_it;
+		while (it != &(label->parts->list.head)) {
+			next_it = it->next;
+			
+			p = list_get_instance(it, mbr_part_t, link);
+			if (mbr_get_flag(p, ST_LOGIC)) {
+				list_remove(it);
+				label->parts->n_logical -= 1;
+				mbr_free_partition(p);
+			}
+			
+			it = next_it;
+		}
+		
+	}
+	
+	/* Remove the partition itself */
+	p = list_get_instance(l, mbr_part_t, link);
+	if (mbr_get_flag(p, ST_LOGIC)) {
+		label->parts->n_logical -= 1;
+		list_remove(l);
+		mbr_free_partition(p);
+	} else {
+		/* Cannot remove primary - it would break ordering, just zero it */
+		label->parts->n_primary -= 1;
+		p->type = 0;
+		p->status = 0;
+		p->start_addr = 0;
+		p->length = 0;
+		p->ebr_addr = 0;
+	}
+	
+	return EOK;
+}
+
+/** mbr_part_t destructor */
+void mbr_free_partition(mbr_part_t *p)
+{
+	if (p->ebr != NULL)
+		free(p->ebr);
+	free(p);
+}
+
+/** Get flag bool value */
+int mbr_get_flag(mbr_part_t *p, MBR_FLAGS flag)
+{
+	return (p->status & (1 << flag)) ? 1 : 0;
+}
+
+/** Set a specifig status flag to a value */
+void mbr_set_flag(mbr_part_t *p, MBR_FLAGS flag, bool value)
+{
+	uint16_t status = p->status;
+
+	if (value)
+		status = status | (1 << flag);
+	else
+		status = status ^ (status & (1 << flag));
+
+	p->status = status;
+}
+
+/** Get next aligned address */
+uint32_t mbr_get_next_aligned(uint32_t addr, unsigned int alignment)
+{
+	uint32_t div = addr / alignment;
+	return (div + 1) * alignment;
+}
+
+list_t * mbr_get_list(mbr_label_t *label)
+{
+	if (label->parts != NULL)
+		return &(label->parts->list);
+	else
+		return NULL;
+}
+
+mbr_part_t * mbr_get_first_partition(mbr_label_t *label)
+{
+	list_t *list = mbr_get_list(label);
+	if (list != NULL && !list_empty(list))
+		return list_get_instance(list->head.next, mbr_part_t, link);
+	else
+		return NULL;
+}
+
+mbr_part_t * mbr_get_next_partition(mbr_label_t *label, mbr_part_t *p)
+{
+	list_t *list = mbr_get_list(label);
+	if (list != NULL && &(p->link) != list_last(list))
+		return list_get_instance(p->link.next, mbr_part_t, link);
+	else
+		return NULL;
+}
+
+/** Just a wrapper for free() */
+void mbr_free_mbr(mbr_t *mbr)
+{
+	free(mbr);
+}
+
+/** Free partition list
+ *
+ * @param parts		partition list to be freed
+ */
+void mbr_free_partitions(mbr_partitions_t *parts)
+{
+	list_foreach_safe(parts->list, cur_link, next) {
+		mbr_part_t *p = list_get_instance(cur_link, mbr_part_t, link);
+		list_remove(cur_link);
+		mbr_free_partition(p);
+	}
+
+	free(parts);
+}
+
+/* Internal functions follow */
+
+static br_block_t *alloc_br()
+{
+	br_block_t *br = malloc(sizeof(br_block_t));
+	if (br == NULL)
+		return NULL;
+	
+	memset(br, 0, 512);
+	br->signature = host2uint16_t_le(BR_SIGNATURE);
+	
+	return br;
+}
+
+/** Parse partition entry to mbr_part_t
+ * @return		returns 1, if extended partition, 0 otherwise
+ * */
+static int decode_part(pt_entry_t *src, mbr_part_t *trgt, uint32_t base)
+{
+	trgt->type = src->ptype;
+
+	trgt->status = (trgt->status & 0xFF00) | (uint16_t) src->status;
+
+	trgt->start_addr = uint32_t_le2host(src->first_lba) + base;
+	trgt->length = uint32_t_le2host(src->length);
+
+	return (src->ptype == PT_EXTENDED) ? 1 : 0;
+}
+
+/** Parse MBR contents to mbr_part_t list */
+static int decode_logical(mbr_label_t *label, mbr_part_t * ext)
+{
+	int rc;
+	mbr_part_t *p;
+
+	if (ext == NULL)
+		return EOK;
+
+	uint32_t base = ext->start_addr;
+	uint32_t addr = base;
+	br_block_t *ebr;
+	
+	rc = block_init(EXCHANGE_ATOMIC, label->device, 512);
+	if (rc != EOK)
+		return rc;
+	
+	ebr = alloc_br();
+	if (ebr == NULL) {
+		rc = ENOMEM;
+		goto end;
+	}
+	
+	rc = block_read_direct(label->device, addr, 1, ebr);
+	if (rc != EOK) {
+		goto free_ebr_end;
+	}
+	
+	if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
+		rc = EINVAL;
+		goto free_ebr_end;
+	}
+	
+	if (ebr->pte[0].ptype == PT_UNUSED) {
+		rc = EOK;
+		goto free_ebr_end;
+	}
+	
+	p = mbr_alloc_partition();
+	if (p == NULL) {
+		rc = ENOMEM;
+		goto free_ebr_end;
+	}
+	
+	decode_part(&(ebr->pte[0]), p, base);
+	mbr_set_flag(p, ST_LOGIC, true);
+	p->ebr = ebr;
+	p->ebr_addr = addr;
+	rc = mbr_add_partition(label, p);
+	if (rc != ERR_OK) 
+		return EINVAL;
+	
+	addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
+	
+	while (ebr->pte[1].ptype != PT_UNUSED) {
+		
+		ebr = alloc_br();
+		if (ebr == NULL) {
+			rc = ENOMEM;
+			goto end;
+		}
+		
+		rc = block_read_direct(label->device, addr, 1, ebr);
+		if (rc != EOK) {
+			goto free_ebr_end;
+		}
+		
+		if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
+			rc = EINVAL;
+			goto free_ebr_end;
+		}
+		
+		p = mbr_alloc_partition();
+		if (p == NULL) {
+			rc = ENOMEM;
+			goto free_ebr_end;
+		}
+		
+		decode_part(&(ebr->pte[0]), p, addr);
+		mbr_set_flag(p, ST_LOGIC, true);
+		p->ebr = ebr;
+		p->ebr_addr = addr;
+		rc = mbr_add_partition(label, p);
+		if (rc != ERR_OK)
+			return EINVAL;
+		
+		addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
+	}
+	
+	rc = EOK;
+	goto end;
+	
+free_ebr_end:
+	free(ebr);
+	
+end:
+	block_fini(label->device);
+	
+	return rc;
+}
+
+/** Convert mbr_part_t to pt_entry_t */
+static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr)
+{
+	if (src != NULL) {
+		trgt->status = (uint8_t) (src->status & 0xFF);
+		/* ingoring CHS */
+		trgt->first_chs[0] = 0xFE;
+		trgt->first_chs[1] = 0xFF;
+		trgt->first_chs[2] = 0xFF;
+		trgt->last_chs[0] = 0xFE;
+		trgt->last_chs[1] = 0xFF;
+		trgt->last_chs[2] = 0xFF;
+		if (ebr) {	/* encoding reference to EBR */
+			trgt->ptype = PT_EXTENDED_LBA;
+			trgt->first_lba = host2uint32_t_le(src->ebr_addr - base);
+			trgt->length = host2uint32_t_le(src->length + src->start_addr - src->ebr_addr);
+		} else {	/* encoding reference to partition */
+			trgt->ptype = src->type;
+			trgt->first_lba = host2uint32_t_le(src->start_addr - base);
+			trgt->length = host2uint32_t_le(src->length);
+		}
+		
+		if (trgt->ptype == PT_UNUSED)
+			memset(trgt, 0, sizeof(pt_entry_t));
+	} else {
+		memset(trgt, 0, sizeof(pt_entry_t));
+	}
+}
+
+/** Check whether two partitions overlap
+ * 
+ * @return		true/false
+ */
+static bool check_overlap(mbr_part_t * p1, mbr_part_t * p2)
+{
+	if (p1->start_addr < p2->start_addr && p1->start_addr + p1->length <= p2->start_addr) {
+		return false;
+	} else if (p1->start_addr > p2->start_addr && p2->start_addr + p2->length <= p1->start_addr) {
+		return false;
+	}
+
+	return true;
+}
+
+/** Check whether one partition encapsulates the other
+ * 
+ * @return		true/false
+ */
+static bool check_encaps(mbr_part_t * inner, mbr_part_t * outer)
+{
+	if (inner->start_addr <= outer->start_addr || outer->start_addr + outer->length <= inner->start_addr) {
+		return false;
+	} else if (outer->start_addr + outer->length < inner->start_addr + inner->length) {
+		return false;
+	}
+
+	return true;
+}
+
+/** Check whether one partition preceeds the other
+ * 
+ * @return		true/false
+ */
+static bool check_preceeds(mbr_part_t * preceeder, mbr_part_t * precedee)
+{
+	return preceeder->start_addr < precedee->start_addr;
+}
+
+mbr_err_val mbr_add_primary(mbr_label_t *label, mbr_part_t *p)
+{
+	if (label->parts->n_primary == 4) {
+		return ERR_PRIMARY_FULL;
+	}
+	
+	/* Check if partition makes space for MBR itself. */
+	if (p->start_addr == 0) {
+		return ERR_OUT_BOUNDS;
+	}
+	
+	/* if it's extended, is there any other one? */
+	if ((p->type == PT_EXTENDED || p->type == PT_EXTENDED_LBA) && label->parts->l_extended != NULL) {
+		return ERR_EXTENDED_PRESENT;
+	}
+	
+	/* find a place and add it */
+	mbr_part_t *iter;
+	mbr_part_t *empty = NULL;
+	mbr_part_foreach(label, iter) {
+		if (iter->type == PT_UNUSED) {
+			if (empty == NULL)
+				empty = iter;
+		} else if (check_overlap(p, iter))
+			return ERR_OVERLAP;
+	}
+	
+	list_insert_after(&(p->link), &(empty->link));
+	list_remove(&(empty->link));
+	free(empty);
+	
+	label->parts->n_primary += 1;
+	
+	if (p->type == PT_EXTENDED || p->type == PT_EXTENDED_LBA)
+		label->parts->l_extended = &(p->link);
+	
+	return EOK;
+}
+
+mbr_err_val mbr_add_logical(mbr_label_t *label, mbr_part_t *p)
+{
+	/* is there any extended partition? */
+	if (label->parts->l_extended == NULL)
+		return ERR_NO_EXTENDED;
+	
+	/* is the logical partition inside the extended one? */
+	mbr_part_t *ext = list_get_instance(label->parts->l_extended, mbr_part_t, link);
+	if (!check_encaps(p, ext))
+		return ERR_OUT_BOUNDS;
+	
+	/* find a place for the new partition in a sorted linked list */
+	bool first_logical = true;
+	mbr_part_t *iter;
+	mbr_part_foreach (label, iter) {
+		if (mbr_get_flag(iter, ST_LOGIC)) {
+			if (check_overlap(p, iter)) 
+				return ERR_OVERLAP;
+			if (check_preceeds(iter, p)) {
+				/* checking if there's at least one sector of space preceeding */
+				if ((iter->start_addr + iter->length) >= p->start_addr - 1)
+					return ERR_NO_EBR;
+			} else if (first_logical){
+				/* First logical partition's EBR is before every other
+				 * logical partition. Thus we don't check if this partition
+				 * leaves enough space for it. */
+				first_logical = false;
+			} else {
+				/* checking if there's at least one sector of space following (for following partitions's EBR) */
+				if ((p->start_addr + p->length) >= iter->start_addr - 1)
+					return ERR_NO_EBR;
+			}
+		}
+	}
+	
+	/* alloc EBR if it's not already there */
+	if (p->ebr == NULL) {
+		p->ebr = alloc_br();
+		if (p->ebr == NULL) {
+			return ERR_NOMEM;
+		}
+	}
+	
+	/* add it */
+	list_append(&(p->link), &(label->parts->list));
+	label->parts->n_logical += 1;
+	
+	return EOK;
+}
+
+
+
Index: uspace/lib/mbr/libmbr.h
===================================================================
--- uspace/lib/mbr/libmbr.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/mbr/libmbr.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /** @addtogroup libmbr
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBMBR_LIBMBR_H_
+#define LIBMBR_LIBMBR_H_
+
+#include <sys/types.h>
+#include "mbr.h"
+
+#define LIBMBR_NAME	"libmbr"
+
+typedef enum {
+	/** Other flags unknown - saving previous state */
+	/** Bootability */
+	ST_BOOT = 7,
+	/** Logical partition, 0 = primary, 1 = logical*/
+	ST_LOGIC = 8
+} MBR_FLAGS;
+
+typedef enum {
+	/** No error */
+	ERR_OK = 0,
+	/** All primary partitions already present */
+	ERR_PRIMARY_FULL,
+	/** Extended partition already present */
+	ERR_EXTENDED_PRESENT,
+	/** No extended partition present */
+	ERR_NO_EXTENDED,
+	/** Partition overlapping */
+	ERR_OVERLAP,
+	/** Partition out of bounds */
+	ERR_OUT_BOUNDS,
+	/** No space left for EBR */
+	ERR_NO_EBR,
+	/** Out of memory */
+	ERR_NOMEM,
+	/** Libblock error */
+	ERR_LIBBLOCK,
+} mbr_err_val;
+
+/** MBR header */
+typedef struct {
+	/** Raw access to data */
+	br_block_t raw_data;
+} mbr_t;
+
+
+/** Partition */
+typedef struct mbr_part {
+	/** The link in the doubly-linked list */
+	link_t link;
+	/** Partition type */
+	uint8_t type;
+	/** Flags */
+	uint16_t status;
+	/** Address of first block */
+	uint32_t start_addr;
+	/** Number of blocks */
+	uint32_t length;
+	/** Points to Extended Boot Record of logical partition */
+	br_block_t * ebr;
+	/** EBR address */
+	uint32_t ebr_addr;
+} mbr_part_t;
+
+/** Partition list structure */
+typedef struct mbr_parts {
+	/** Number of primary partitions */
+	unsigned char n_primary;
+	/** Index to the extended partition in the array */
+	link_t * l_extended;
+	/** Number of logical partitions */
+	unsigned int n_logical;
+	/** Logical partition linked list */
+	list_t list;
+} mbr_partitions_t;
+
+/** Both header and partition list */
+typedef struct mbr_label {
+	/** MBR header */
+	mbr_t * mbr;
+	/** Partition list */
+	mbr_partitions_t * parts;
+	/** Device where the data are from (or for) */
+	service_id_t device;
+} mbr_label_t;
+
+/* Alloc complete label structure */
+extern mbr_label_t * mbr_alloc_label(void);
+extern void mbr_set_device(mbr_label_t *, service_id_t);
+
+/* Read/Write MBR header.
+ * WARNING: when changing both header and partitions, write first header,
+ * then partitions. The MBR headers' raw_data is NOT updated to follow
+ * partition changes. */
+extern mbr_t * mbr_alloc_mbr(void);
+extern int mbr_read_mbr(mbr_label_t *, service_id_t);
+extern int mbr_write_mbr(mbr_label_t *, service_id_t);
+extern int mbr_is_mbr(mbr_label_t *);
+
+/* Read/Write/Set MBR partitions.
+ * NOTE: Writing partitions writes the complete header as well. */
+extern int          mbr_read_partitions(mbr_label_t *);
+extern int          mbr_write_partitions(mbr_label_t *, service_id_t);
+extern mbr_part_t * mbr_alloc_partition(void);
+extern mbr_partitions_t * mbr_alloc_partitions(void);
+extern mbr_err_val  mbr_add_partition(mbr_label_t *, mbr_part_t *);
+extern int          mbr_remove_partition(mbr_label_t *, size_t);
+extern int          mbr_get_flag(mbr_part_t *, MBR_FLAGS);
+extern void         mbr_set_flag(mbr_part_t *, MBR_FLAGS, bool);
+extern uint32_t     mbr_get_next_aligned(uint32_t, unsigned int);
+extern list_t *     mbr_get_list(mbr_label_t *);
+extern mbr_part_t * mbr_get_first_partition(mbr_label_t *);
+extern mbr_part_t * mbr_get_next_partition(mbr_label_t *, mbr_part_t *);
+
+#define mbr_part_foreach(label, iterator) \
+        for (iterator  = list_get_instance((label)->parts->list.head.next, mbr_part_t, link); \
+             iterator != list_get_instance(&((label)->parts->list.head), mbr_part_t, link); \
+             iterator  = list_get_instance(iterator->link.next, mbr_part_t, link))
+
+
+/* free() wrapper functions. */
+extern void mbr_free_label(mbr_label_t *);
+extern void mbr_free_mbr(mbr_t *);
+extern void mbr_free_partition(mbr_part_t *);
+extern void mbr_free_partitions(mbr_partitions_t *);
+
+#endif
+
Index: uspace/lib/mbr/mbr.h
===================================================================
--- uspace/lib/mbr/mbr.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
+++ uspace/lib/mbr/mbr.h	(revision 07733961aa0e69f8ccc3a986068ad31674911dbe)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /** @addtogroup libmbr
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBMBR_MBR_H_
+#define LIBMBR_MBR_H_
+
+#include <sys/types.h>
+
+/** Number of primary partition records */
+#define N_PRIMARY		4
+
+/** Boot record signature */
+#define BR_SIGNATURE	0xAA55
+
+enum {
+	/** Non-bootable */
+	B_INACTIVE = 0x00,
+	/** Bootable */
+	B_ACTIVE = 0x80,
+	/** Anything else means invalid */
+};
+
+enum {
+	/** Unused partition entry */
+	PT_UNUSED	= 0x00,
+	/** Extended partition */
+	PT_EXTENDED	= 0x05,
+	/** Extended partition with LBA */
+	PT_EXTENDED_LBA	= 0x0F,
+	/** GPT Protective partition */
+	PT_GPT	= 0xEE,
+};
+
+/** Structure of a partition table entry */
+typedef struct {
+	uint8_t status;
+	/** CHS of fist block in partition */
+	uint8_t first_chs[3];
+	/** Partition type */
+	uint8_t ptype;
+	/** CHS of last block in partition */
+	uint8_t last_chs[3];
+	/** LBA of first block in partition */
+	uint32_t first_lba;
+	/** Number of blocks in partition */
+	uint32_t length;
+} __attribute__((packed)) pt_entry_t;
+
+/** Structure of a boot-record block */
+typedef struct {
+	/** Area for boot code */
+	uint8_t code_area[440];
+	/** Optional media ID */
+	uint32_t media_id;
+	/** Padding */
+	uint16_t pad0;
+	/** Partition table entries */
+	pt_entry_t pte[N_PRIMARY];
+	/** Boot record block signature (@c BR_SIGNATURE) */
+	uint16_t signature;
+} __attribute__((packed)) br_block_t;
+
+#endif
+
