Index: tools/check.sh
===================================================================
--- tools/check.sh	(revision 001307cf739bf07517cf923a8ed5eaf6da6121e7)
+++ tools/check.sh	(revision d3ee35b0ef57b3dc1f5a3d5329e81e742ab946b9)
@@ -66,5 +66,5 @@
 do
 	echo -n ">>>> Building $P... "
-	( make distclean && make PROFILE=$P HANDS_OFF=y $1 ) >>/dev/null 2>>/dev/null
+	( make distclean && make PROFILE=$P HANDS_OFF=y "$@" ) >>/dev/null 2>>/dev/null
 	if [ $? -ne 0 ];
 	then
Index: tools/mkfat.py
===================================================================
--- tools/mkfat.py	(revision 001307cf739bf07517cf923a8ed5eaf6da6121e7)
+++ tools/mkfat.py	(revision d3ee35b0ef57b3dc1f5a3d5329e81e742ab946b9)
@@ -168,47 +168,106 @@
 """
 
-def mangle_fname(name):
+LFN_ENTRY = """little:
+	uint8_t pos
+	uint16_t name1[5]
+	uint8_t attr
+	uint8_t type
+	uint8_t csum
+	uint16_t name2[6]
+	uint16_t fc
+	uint16_t name3[2]
+"""
+
+# Global variable to hold the file names in 8.3 format. Needed to 
+# keep track of "number" when creating a short fname from a LFN.
+name83_list = []
+
+def name83(fname):
+	"Create a 8.3 name for the given fname"
+
 	# FIXME: filter illegal characters
-	parts = name.split('.')
-	
+	parts = fname.split('.')
+	
+	name = ''
+	ext = ''
+	lfn = False
+
+	if len(fname) > 11 :
+		lfn = True
+
 	if len(parts) > 0:
-		fname = parts[0]
-	else:
-		fname = ''
-	
-	if len(fname) > 8:
-		sys.stdout.write("mkfat.py: error: Directory entry " + name +
-		    " base name is longer than 8 characters\n")
-		sys.exit(1);
-	
-	return (fname + '          ').upper()[0:8]
-
-def mangle_ext(name):
-	# FIXME: filter illegal characters
-	parts = name.split('.')
-	
-	if len(parts) > 1:
-		ext = parts[1]
-	else:
-		ext = ''
-	
-	if len(parts) > 2:
-		sys.stdout.write("mkfat.py: error: Directory entry " + name +
-		    " has more than one extension\n")
-		sys.exit(1);
-	
-	if len(ext) > 3:
-		sys.stdout.write("mkfat.py: error: Directory entry " + name +
-		    " extension is longer than 3 characters\n")
-		sys.exit(1);
-	
-	return (ext + '   ').upper()[0:3]
+		name = parts[0]
+		if len(name) > 8 :
+			lfn = True
+
+	if len(parts) > 1 :
+		ext = parts[-1]
+		if len(ext) > 3 :
+			lfn = True
+
+	if len(parts) > 2 :
+		lfn = True
+
+	if (lfn == False) :
+		return (name.ljust(8)[0:8], ext.ljust(3)[0:3], False)
+
+	# For filenames with multiple extensions, we treat the last one
+	# as the actual extension. The rest of the filename is stripped
+	# of dots and concatenated to form the short name
+	for _name in parts[1:-1]:
+		name = name + _name		
+
+	global name83_list
+	for number in range(1, 10000) :
+		number_str = '~' + str(number)
+
+		if len(name) + len(number_str) > 8 :
+			name = name[0:8 - len(number_str)]
+
+		name = name + number_str;
+
+		if (name + ext) not in name83_list :
+			break
+			
+	name83_list.append(name + ext)	
+
+	return (name.ljust(8)[0:8], ext.ljust(3)[0:3], True)
+
+def get_utf16(name, l) :
+	"Create a int array out of a string which we can store in uint16_t arrays"
+
+	bs = [0xFFFF for i in range(l)]
+
+	for i in range(len(name)) :
+		bs[i] = ord(name[i])
+	
+	if (len(name) < l) :
+		bs[len(name)] = 0;
+	
+	return bs
+
+def create_lfn_entry((name, index)) :
+	entry = xstruct.create(LFN_ENTRY)
+
+	entry.name1 = get_utf16(name[0:5], 5)
+	entry.name2 = get_utf16(name[5:11], 6)
+	entry.name3 = get_utf16(name[11:13], 2)
+	entry.pos = index
+
+	entry.attr = 0xF
+	entry.fc = 0
+	entry.type = 0
+
+	return entry
 
 def create_dirent(name, directory, cluster, size):
+	
 	dir_entry = xstruct.create(DIR_ENTRY)
 	
-	dir_entry.name = mangle_fname(name).encode('ascii')
-	dir_entry.ext = mangle_ext(name).encode('ascii')
-	
+	dir_entry.name, dir_entry.ext, lfn = name83(name)
+
+	dir_entry.name = dir_entry.name.upper().encode('ascii')
+	dir_entry.ext = dir_entry.ext.upper().encode('ascii')
+
 	if (directory):
 		dir_entry.attr = 0x30
@@ -230,5 +289,27 @@
 		dir_entry.size = size
 	
-	return dir_entry
+
+	if not lfn:
+		return [dir_entry]
+
+	n = len(name) / 13 + 1
+	names = [(name[i * 13: (i + 1) * 13 + 1], i + 1) for i in range(n)]
+
+	entries = sorted(map (create_lfn_entry, names), reverse = True, key = lambda e : e.pos)
+	entries[0].pos |= 0x40
+
+	fname11 = dir_entry.name + dir_entry.ext
+
+	csum = 0
+	for i in range(0, 11) :
+		csum = ((csum & 1) << 7) + (csum  >> 1) + ord(fname11[i])
+		csum = csum & 0xFF
+	
+	for e in entries :
+		e.csum = csum;
+	
+	entries.append(dir_entry)
+
+	return entries
 
 def create_dot_dirent(empty_cluster):
@@ -288,8 +369,8 @@
 		if item.is_file:
 			rv = write_file(item, outf, cluster_size, data_start, fat, reserved_clusters)
-			directory.append(create_dirent(item.name, False, rv[0], rv[1]))
+			directory.extend(create_dirent(item.name, False, rv[0], rv[1]))
 		elif item.is_dir:
 			rv = recursion(False, item.path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
-			directory.append(create_dirent(item.name, True, rv[0], rv[1]))
+			directory.extend(create_dirent(item.name, True, rv[0], rv[1]))
 	
 	if (head):
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 001307cf739bf07517cf923a8ed5eaf6da6121e7)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision d3ee35b0ef57b3dc1f5a3d5329e81e742ab946b9)
@@ -52,6 +52,6 @@
 #define CAT_VERSION "0.0.1"
 #define CAT_DEFAULT_BUFLEN 1024
-
-static const char *cat_oops = "That option is not yet supported\n";
+#define CAT_FULL_FILE 0
+
 static const char *hexchars = "0123456789abcdef";
 
@@ -163,10 +163,12 @@
 }
 
-static unsigned int cat_file(const char *fname, size_t blen, bool hex)
+static unsigned int cat_file(const char *fname, size_t blen, bool hex,
+    off64_t head, off64_t tail, bool tail_first)
 {
 	int fd, bytes = 0, count = 0, reads = 0;
 	char *buff = NULL;
 	int i;
-	size_t offset = 0;
+	size_t offset = 0, copied_bytes = 0;
+	off64_t file_size = 0, length = 0;
 
 	fd = open(fname, O_RDONLY);
@@ -183,8 +185,34 @@
 	}
 
+	if (tail != CAT_FULL_FILE) {
+		file_size = lseek(fd, 0, SEEK_END);
+		if (head == CAT_FULL_FILE) {
+			head = file_size;
+			length = tail;
+		} else if (tail_first) {
+			length = head;
+		} else {
+			if (tail > head)
+				tail = head;
+			length = tail;
+		}
+
+		if (tail_first) {
+			lseek(fd, (tail >= file_size) ? 0 : (file_size - tail), SEEK_SET);
+		} else {
+			lseek(fd, ((head - tail) >= file_size) ? 0 : (head - tail), SEEK_SET);
+		}
+	} else
+		length = head;
+
 	do {
-		bytes = read(fd, buff, blen);
+		bytes = read(fd, buff + copied_bytes, (
+			(length != CAT_FULL_FILE && length - (off64_t)count <= (off64_t)(blen - copied_bytes)) ?
+			(size_t)(length - count) :
+			(blen - copied_bytes) ) );
+		bytes += copied_bytes;
+		copied_bytes = 0;
+
 		if (bytes > 0) {
-			count += bytes;
 			buff[bytes] = '\0';
 			offset = 0;
@@ -193,4 +221,5 @@
 					paged_char(hexchars[((uint8_t)buff[i])/16]);
 					paged_char(hexchars[((uint8_t)buff[i])%16]);
+					paged_char(((count+i+1) & 0xf) == 0 ? '\n' : ' ');
 				}
 				else {
@@ -199,4 +228,10 @@
 						/* Reached end of string */
 						break;
+					} else if (c == U_SPECIAL && offset + 2 >= (size_t)bytes) {
+						/* If an extended character is cut off due to the size of the buffer,
+						   we will copy it over to the next buffer so it can be read correctly. */
+						copied_bytes = bytes - offset + 1;
+						memcpy(buff, buff + offset - 1, copied_bytes);
+						break;
 					}
 					paged_char(c);
@@ -204,7 +239,8 @@
 				
 			}
+			count += bytes;
 			reads++;
 		}
-	} while (bytes > 0 && !should_quit);
+	} while (bytes > 0 && !should_quit && (count < length || length == CAT_FULL_FILE));
 
 	close(fd);
@@ -223,8 +259,11 @@
 int cmd_cat(char **argv)
 {
-	unsigned int argc, i, ret = 0, buffer = 0;
+	unsigned int argc, i, ret = 0;
+	size_t buffer = 0;
 	int c, opt_ind;
+	aoff64_t head = CAT_FULL_FILE, tail = CAT_FULL_FILE;
 	bool hex = false;
 	bool more = false;
+	bool tailFirst = false;
 	sysarg_t rows, cols;
 	int rc;
@@ -254,11 +293,22 @@
 			return CMD_SUCCESS;
 		case 'H':
-			printf("%s", cat_oops);
-			return CMD_FAILURE;
+			if (!optarg || str_uint64_t(optarg, NULL, 10, false, &head) != EOK ) {
+				puts("Invalid head size\n");
+				return CMD_FAILURE;
+			}
+			break;
 		case 't':
-			printf("%s", cat_oops);
-			return CMD_FAILURE;
+			if (!optarg || str_uint64_t(optarg, NULL, 10, false, &tail) != EOK ) {
+				puts("Invalid tail size\n");
+				return CMD_FAILURE;
+			}
+			if (head == CAT_FULL_FILE)
+				tailFirst = true;
+			break;
 		case 'b':
-			printf("%s", cat_oops);
+			if (!optarg || str_size_t(optarg, NULL, 10, false, &buffer) != EOK ) {
+				puts("Invalid buffer size\n");
+				return CMD_FAILURE;
+			}
 			break;
 		case 'm':
@@ -279,5 +329,5 @@
 	}
 
-	if (buffer <= 0)
+	if (buffer < 4)
 		buffer = CAT_DEFAULT_BUFLEN;
 	
@@ -295,5 +345,5 @@
 
 	for (i = optind; argv[i] != NULL && !should_quit; i++)
-		ret += cat_file(argv[i], buffer, hex);
+		ret += cat_file(argv[i], buffer, hex, head, tail, tailFirst);
 
 	if (ret)
Index: uspace/app/bdsh/cmds/modules/cat/cat.h
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.h	(revision 001307cf739bf07517cf923a8ed5eaf6da6121e7)
+++ uspace/app/bdsh/cmds/modules/cat/cat.h	(revision d3ee35b0ef57b3dc1f5a3d5329e81e742ab946b9)
@@ -4,5 +4,5 @@
 /* Prototypes for the cat command, excluding entry points */
 
-static unsigned int cat_file(const char *, size_t, bool);
+static unsigned int cat_file(const char *, size_t, bool, off64_t, off64_t, bool);
 
 #endif /* CAT_H */
