linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] update udev_volume_id
@ 2004-06-24  0:44 Kay Sievers
  2004-06-26  0:29 ` Greg KH
  0 siblings, 1 reply; 4+ messages in thread
From: Kay Sievers @ 2004-06-24  0:44 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 342 bytes --]

Hey, seems its's update time for the tools in the extras/ folder these
days, so I will not stand behind :)

volume_id is now able to read NTFS labels. Not very exciting, but we
keep up to date with the version in HAL. Also __packed__ was needed for
the structs, cause the gcc 3.4 compiled version was no longer working
properly.

Thanks,
Kay

[-- Attachment #2: udev-volume_id.patch --]
[-- Type: text/plain, Size: 19553 bytes --]

===== extras/volume_id/volume_id.c 1.3 vs edited =====
--- 1.3/extras/volume_id/volume_id.c	2004-05-08 22:43:17 +02:00
+++ edited/extras/volume_id/volume_id.c	2004-06-24 02:25:42 +02:00
@@ -7,7 +7,7 @@
  *	the e2fsprogs. This is a simple straightforward implementation for
  *	reading the label strings of only the most common filesystems.
  *	If you need a full featured library with attribute caching, support for
- *	much more partition/media types or non-root data access, you may have
+ *	much more partition/media types or non-root disk access, you may have
  *	a look at:
  *		http://e2fsprogs.sourceforge.net.
  *
@@ -26,6 +26,10 @@
  *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -55,12 +59,23 @@
 			   (((__u32)(x) & 0x0000ff00u) <<  8) | \
 			   (((__u32)(x) & 0x000000ffu) << 24))
 
+#define bswap64(x) (__u64)((((__u64)(x) & 0xff00000000000000u) >> 56) | \
+			   (((__u64)(x) & 0x00ff000000000000u) >> 40) | \
+			   (((__u64)(x) & 0x0000ff0000000000u) >> 24) | \
+			   (((__u64)(x) & 0x000000ff00000000u) >>  8) | \
+			   (((__u64)(x) & 0x00000000ff000000u) <<  8) | \
+			   (((__u64)(x) & 0x0000000000ff0000u) << 24) | \
+			   (((__u64)(x) & 0x000000000000ff00u) << 40) | \
+			   (((__u64)(x) & 0x00000000000000ffu) << 56))
+
 #if (__BYTE_ORDER == __LITTLE_ENDIAN) 
 #define le16_to_cpu(x) (x)
 #define le32_to_cpu(x) (x)
+#define le64_to_cpu(x) (x)
 #elif (__BYTE_ORDER == __BIG_ENDIAN)
 #define le16_to_cpu(x) bswap16(x)
 #define le32_to_cpu(x) bswap32(x)
+#define le64_to_cpu(x) bswap64(x)
 #endif
 
 /* size of superblock buffer, reiser block is at 64k */
@@ -69,15 +84,17 @@
 #define SEEK_BUFFER_SIZE			0x800
 
 
-static void set_label_raw(struct volume_id *id, char *buf, int count)
+static void set_label_raw(struct volume_id *id,
+			  const __u8 *buf, unsigned int count)
 {
 	memcpy(id->label_raw, buf, count);
 	id->label_raw_len = count;
 }
 
-static void set_label_string(struct volume_id *id, char *buf, int count)
+static void set_label_string(struct volume_id *id,
+			     const __u8 *buf, unsigned int count)
 {
-	int i;
+	unsigned int i;
 
 	memcpy(id->label_string, buf, count);
 
@@ -90,9 +107,42 @@
 	id->label_string[i+1] = '\0';
 }
 
-static void set_uuid(struct volume_id *id, unsigned char *buf, int count)
+#define LE		0
+#define BE		1
+static void set_label_unicode16(struct volume_id *id,
+				const __u8 *buf,
+				unsigned int endianess,
+				unsigned int count)
+{
+	unsigned int i, j;
+	__u16 c;
+
+	j = 0;
+	for (i = 0; i <= count-2; i += 2) {
+		if (endianess == LE)
+			c = (buf[i+1] << 8) | buf[i];
+		else
+			c = (buf[i] << 8) | buf[i+1];
+		if (c == 0) {
+			id->label_string[j] = '\0';
+			break;
+		} else if (c < 0x80) {
+			id->label_string[j++] = (__u8) c;
+		} else if (c < 0x800) {
+			id->label_string[j++] = (__u8) (0xc0 | (c >> 6));
+			id->label_string[j++] = (__u8) (0x80 | (c & 0x3f));
+		} else {
+			id->label_string[j++] = (__u8) (0xe0 | (c >> 12));
+			id->label_string[j++] = (__u8) (0x80 | ((c >> 6) & 0x3f));
+			id->label_string[j++] = (__u8) (0x80 | (c & 0x3f));
+		}
+	}
+}
+
+static void set_uuid(struct volume_id *id,
+		     const __u8 *buf, unsigned int count)
 {
-	int i;
+	unsigned int i;
 
 	memcpy(id->uuid, buf, count);
 
@@ -121,9 +171,10 @@
 	}
 }
 
-static char *get_buffer(struct volume_id *id, size_t off, size_t len)
+static __u8 *get_buffer(struct volume_id *id,
+			unsigned long off, unsigned int len)
 {
-	size_t buf_len;
+	unsigned int buf_len;
 
 	/* check if requested area fits in superblock buffer */
 	if (off + len <= SB_BUFFER_SIZE) {
@@ -135,8 +186,8 @@
 
 		/* check if we need to read */
 		if ((off + len) > id->sbbuf_len) {
-			dbg("read sbbuf len:0x%x", off + len);
-			lseek(id->fd, 0, SEEK_SET);
+			dbg("read sbbuf len:0x%lx", off + len);
+			lseek64(id->fd, 0, SEEK_SET);
 			buf_len = read(id->fd, id->sbbuf, off + len);
 			id->sbbuf_len = buf_len;
 			if (buf_len < off + len)
@@ -158,9 +209,10 @@
 		/* check if we need to read */
 		if ((off < id->seekbuf_off) ||
 		    ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
-			dbg("read seekbuf off:0x%x len:0x%x", off, len);
-			lseek(id->fd, off, SEEK_SET);
+			dbg("read seekbuf off:0x%lx len:0x%x", off, len);
+			lseek64(id->fd, off, SEEK_SET);
 			buf_len = read(id->fd, id->seekbuf, len);
+			dbg("got 0x%x (%i) bytes", buf_len, buf_len);
 			id->seekbuf_off = off;
 			id->seekbuf_len = buf_len;
 			if (buf_len < len)
@@ -191,23 +243,23 @@
 static int probe_ext(struct volume_id *id)
 {
 	struct ext2_super_block {
-		__u32		inodes_count;
-		__u32		blocks_count;
-		__u32		r_blocks_count;
-		__u32		free_blocks_count;
-		__u32		free_inodes_count;
-		__u32		first_data_block;
-		__u32		log_block_size;
-		__u32		dummy3[7];
-		unsigned char	magic[2];
-		__u16		state;
-		__u32		dummy5[8];
-		__u32		feature_compat;
-		__u32		feature_incompat;
-		__u32		feature_ro_compat;
-		unsigned char	uuid[16];
-		char		volume_name[16];
-	} *es;
+		__u32	inodes_count;
+		__u32	blocks_count;
+		__u32	r_blocks_count;
+		__u32	free_blocks_count;
+		__u32	free_inodes_count;
+		__u32	first_data_block;
+		__u32	log_block_size;
+		__u32	dummy3[7];
+		__u8	magic[2];
+		__u16	state;
+		__u32	dummy5[8];
+		__u32	feature_compat;
+		__u32	feature_incompat;
+		__u32	feature_ro_compat;
+		__u8	uuid[16];
+		__u8	volume_name[16];
+	} __attribute__((__packed__)) *es;
 
 	es = (struct ext2_super_block *)
 	     get_buffer(id, EXT_SUPERBLOCK_OFFSET, 0x200);
@@ -239,20 +291,20 @@
 static int probe_reiser(struct volume_id *id)
 {
 	struct reiser_super_block {
-		__u32		blocks_count;
-		__u32		free_blocks;
-		__u32		root_block;
-		__u32		journal_block;
-		__u32		journal_dev;
-		__u32		orig_journal_size;
-		__u32		dummy2[5];
-		__u16		blocksize;
-		__u16		dummy3[3];
-		unsigned char	magic[12];
-		__u32		dummy4[5];
-		unsigned char	uuid[16];
-		char		label[16];
-	} *rs;
+		__u32	blocks_count;
+		__u32	free_blocks;
+		__u32	root_block;
+		__u32	journal_block;
+		__u32	journal_dev;
+		__u32	orig_journal_size;
+		__u32	dummy2[5];
+		__u16	blocksize;
+		__u16	dummy3[3];
+		__u8	magic[12];
+		__u32	dummy4[5];
+		__u8	uuid[16];
+		__u8	label[16];
+	} __attribute__((__packed__)) *rs;
 
 	rs = (struct reiser_super_block *)
 	     get_buffer(id, REISER_SUPERBLOCK_OFFSET, 0x200);
@@ -288,19 +340,19 @@
 static int probe_xfs(struct volume_id *id)
 {
 	struct xfs_super_block {
-		unsigned char	magic[4];
-		__u32		blocksize;
-		__u64		dblocks;
-		__u64		rblocks;
-		__u32		dummy1[2];
-		unsigned char	uuid[16];
-		__u32		dummy2[15];
-		char		fname[12];
-		__u32		dummy3[2];
-		__u64		icount;
-		__u64		ifree;
-		__u64		fdblocks;
-	} *xs;
+		__u8	magic[4];
+		__u32	blocksize;
+		__u64	dblocks;
+		__u64	rblocks;
+		__u32	dummy1[2];
+		__u8	uuid[16];
+		__u32	dummy2[15];
+		__u8	fname[12];
+		__u32	dummy3[2];
+		__u64	icount;
+		__u64	ifree;
+		__u64	fdblocks;
+	} __attribute__((__packed__)) *xs;
 
 	xs = (struct xfs_super_block *) get_buffer(id, 0, 0x200);
 	if (xs == NULL)
@@ -323,17 +375,17 @@
 static int probe_jfs(struct volume_id *id)
 {
 	struct jfs_super_block {
-		unsigned char	magic[4];
-		__u32		version;
-		__u64		size;
-		__u32		bsize;
-		__u32		dummy1;
-		__u32		pbsize;
-		__u32		dummy2[27];
-		unsigned char	uuid[16];
-		unsigned char	label[16];
-		unsigned char	loguuid[16];
-	} *js;
+		__u8	magic[4];
+		__u32	version;
+		__u64	size;
+		__u32	bsize;
+		__u32	dummy1;
+		__u32	pbsize;
+		__u32	dummy2[27];
+		__u8	uuid[16];
+		__u8	label[16];
+		__u8	loguuid[16];
+	} __attribute__((__packed__)) *js;
 
 	js = (struct jfs_super_block *)
 	     get_buffer(id, JFS_SUPERBLOCK_OFFSET, 0x200);
@@ -356,34 +408,34 @@
 static int probe_vfat(struct volume_id *id)
 {
 	struct vfat_super_block {
-		unsigned char	ignored[3];
-		unsigned char	sysid[8];
-		unsigned char	sector_size[2];
-		__u8		cluster_size;
-		__u16		reserved;
-		__u8		fats;
-		unsigned char	dir_entries[2];
-		unsigned char	sectors[2];
-		unsigned char	media;
-		__u16		fat_length;
-		__u16		secs_track;
-		__u16		heads;
-		__u32		hidden;
-		__u32		total_sect;
-		__u32		fat32_length;
-		__u16		flags;
-		__u8		version[2];
-		__u32		root_cluster;
-		__u16		insfo_sector;
-		__u16		backup_boot;
-		__u16		reserved2[6];
-		unsigned char	unknown[3];
-		unsigned char	serno[4];
-		char		label[11];
-		unsigned char	magic[8];
-		unsigned char	dummy2[164];
-		unsigned char	pmagic[2];
-	} *vs;
+		__u8	ignored[3];
+		__u8	sysid[8];
+		__u8	sector_size[2];
+		__u8	cluster_size;
+		__u16	reserved;
+		__u8	fats;
+		__u8	dir_entries[2];
+		__u8	sectors[2];
+		__u8	media;
+		__u16	fat_length;
+		__u16	secs_track;
+		__u16	heads;
+		__u32	hidden;
+		__u32	total_sect;
+		__u32	fat32_length;
+		__u16	flags;
+		__u8	version[2];
+		__u32	root_cluster;
+		__u16	insfo_sector;
+		__u16	backup_boot;
+		__u16	reserved2[6];
+		__u8	unknown[3];
+		__u8	serno[4];
+		__u8	label[11];
+		__u8	magic[8];
+		__u8	dummy2[164];
+		__u8	pmagic[2];
+	} __attribute__((__packed__)) *vs;
 
 	vs = (struct vfat_super_block *) get_buffer(id, 0, 0x200);
 	if (vs == NULL)
@@ -409,27 +461,27 @@
 static int probe_msdos(struct volume_id *id)
 {
 	struct msdos_super_block {
-		unsigned char	ignored[3];
-		unsigned char	sysid[8];
-		unsigned char	sector_size[2];
-		__u8		cluster_size;
-		__u16		reserved;
-		__u8		fats;
-		unsigned char	dir_entries[2];
-		unsigned char	sectors[2];
-		unsigned char	media;
-		__u16		fat_length;
-		__u16		secs_track;
-		__u16		heads;
-		__u32		hidden;
-		__u32		total_sect;
-		unsigned char	unknown[3];
-		unsigned char	serno[4];
-		char		label[11];
-		unsigned char	magic[8];
-		unsigned char	dummy2[192];
-		unsigned char	pmagic[2];
-	} *ms;
+		__u8	ignored[3];
+		__u8	sysid[8];
+		__u8	sector_size[2];
+		__u8	cluster_size;
+		__u16	reserved;
+		__u8	fats;
+		__u8	dir_entries[2];
+		__u8	sectors[2];
+		__u8	media;
+		__u16	fat_length;
+		__u16	secs_track;
+		__u16	heads;
+		__u32	hidden;
+		__u32	total_sect;
+		__u8	unknown[3];
+		__u8	serno[4];
+		__u8	label[11];
+		__u8	magic[8];
+		__u8	dummy2[192];
+		__u8	pmagic[2];
+	} __attribute__((__packed__)) *ms;
 
 	ms = (struct msdos_super_block *) get_buffer(id, 0, 0x200);
 	if (ms == NULL)
@@ -459,45 +511,43 @@
 {
 	struct volume_descriptor {
 		struct descriptor_tag {
-			__u16		id;
-			__u16		version;
-			unsigned char	checksum;
-			unsigned char	reserved;
-			__u16		serial;
-			__u16		crc;
-			__u16		crc_len;
-			__u32		location;
-		} tag;
+			__u16	id;
+			__u16	version;
+			__u8	checksum;
+			__u8	reserved;
+			__u16	serial;
+			__u16	crc;
+			__u16	crc_len;
+			__u32	location;
+		} __attribute__((__packed__)) tag;
 		union {
 			struct anchor_descriptor {
-				__u32		length;
-				__u32		location;
-			} anchor;
+				__u32	length;
+				__u32	location;
+			} __attribute__((__packed__)) anchor;
 			struct primary_descriptor {
-				__u32		seq_num;
-				__u32		desc_num;
+				__u32	seq_num;
+				__u32	desc_num;
 				struct dstring {
-					char		clen;
-					char		c[31];
-				} ident;
-			} primary;
-		} type;
-	} *vd;
+					__u8	clen;
+					__u8	c[31];
+				} __attribute__((__packed__)) ident;
+			} __attribute__((__packed__)) primary;
+		} __attribute__((__packed__)) type;
+	} __attribute__((__packed__)) *vd;
 
 	struct volume_structure_descriptor {
-		unsigned char	type;
-		char		id[5];
-		unsigned char	version;
+		__u8	type;
+		__u8	id[5];
+		__u8	version;
 	} *vsd;
 
-	size_t bs;
-	size_t b;
-	int type;
-	int count;
-	int loc;
-	int clen;
-	int i,j;
-	int c;
+	unsigned int bs;
+	unsigned int b;
+	unsigned int type;
+	unsigned int count;
+	unsigned int loc;
+	unsigned int clen;
 
 	vsd = (struct volume_structure_descriptor *)
 	      get_buffer(id, UDF_VSD_OFFSET, 0x200);
@@ -594,29 +644,10 @@
 
 	clen = vd->type.primary.ident.clen;
 	dbg("label string charsize=%i bit", clen);
-	if (clen == 8) {
+	if (clen == 8) 
 		set_label_string(id, vd->type.primary.ident.c, 31);
-	} else if (clen == 16) {
-		/* convert unicode OSTA dstring to UTF-8 */
-		j = 0;
-		for (i = 0; i < 32; i += 2) {
-			c = (vd->type.primary.ident.c[i] << 8) |
-			    vd->type.primary.ident.c[i+1];
-			if (c == 0) {
-				id->label_string[j] = '\0';
-				break;
-			}else if (c < 0x80U) {
-				id->label_string[j++] = (char) c;
-			} else if (c < 0x800U) {
-				id->label_string[j++] = (char) (0xc0 | (c >> 6));
-				id->label_string[j++] = (char) (0x80 | (c & 0x3f));
-			} else {
-				id->label_string[j++] = (char) (0xe0 | (c >> 12));
-				id->label_string[j++] = (char) (0x80 | ((c >> 6) & 0x3f));
-				id->label_string[j++] = (char) (0x80 | (c & 0x3f));
-			}
-		}
-	}
+	else if (clen == 16)
+		set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
 
 found:
 	id->fs_type = UDF;
@@ -630,20 +661,20 @@
 {
 	union iso_super_block {
 		struct iso_header {
-			unsigned char	type;
-			char		id[5];
-			unsigned char	version;
-			unsigned char	unused1;
-			char		system_id[32];
-			char		volume_id[32];
-		} iso;
+			__u8	type;
+			__u8	id[5];
+			__u8	version;
+			__u8	unused1;
+			__u8		system_id[32];
+			__u8		volume_id[32];
+		} __attribute__((__packed__)) iso;
 		struct hs_header {
-			char		foo[8];
-			unsigned char	type;
-			char		id[4];
-			unsigned char	version;
-		} hs;
-	} *is;
+			__u8	foo[8];
+			__u8	type;
+			__u8	id[4];
+			__u8	version;
+		} __attribute__((__packed__)) hs;
+	} __attribute__((__packed__)) *is;
 
 	is = (union iso_super_block *)
 	     get_buffer(id, ISO_SUPERBLOCK_OFFSET, 0x200);
@@ -666,12 +697,73 @@
 	return 0;
 }
 
+#define MFT_RECORD_VOLUME			3
+#define MFT_RECORD_ATTR_VOLUME_NAME		0x60u
+#define MFT_RECORD_ATTR_OBJECT_ID		0x40u
+#define MFT_RECORD_ATTR_END			0xffffffffu
 static int probe_ntfs(struct volume_id *id)
 {
 	struct ntfs_super_block {
-		char jump[3];
-		char oem_id[4];
-	} *ns;
+		__u8	jump[3];
+		__u8	oem_id[8];
+		struct bios_param_block {
+			__u16	bytes_per_sector;
+			__u8	sectors_per_cluster;
+			__u16	reserved_sectors;
+			__u8	fats;
+			__u16	root_entries;
+			__u16	sectors;
+			__u8	media_type;		/* 0xf8 = hard disk */
+			__u16	sectors_per_fat;
+			__u16	sectors_per_track;
+			__u16	heads;
+			__u32	hidden_sectors;
+			__u32	large_sectors;
+		} __attribute__((__packed__)) bpb;
+		__u8 unused[4];
+		__u64	number_of_sectors;
+		__u64	mft_cluster_location;
+		__u64	mft_mirror_cluster_location;
+		__s8	cluster_per_mft_record;
+	} __attribute__((__packed__)) *ns;
+
+	struct master_file_table_record {
+		__u8	magic[4];
+		__u16	usa_ofs;
+		__u16	usa_count;
+		__u64	lsn;
+		__u16	sequence_number;
+		__u16	link_count;
+		__u16	attrs_offset;
+		__u16	flags;
+		__u32	bytes_in_use;
+		__u32	bytes_allocated;
+	} __attribute__((__packed__)) *mftr;
+
+	struct file_attribute {
+		__u32	type;
+		__u32	len;
+		__u8	non_resident;
+		__u8	name_len;
+		__u16	name_offset;
+		__u16	flags;
+		__u16	instance;
+		__u32	value_len;
+		__u16	value_offset;
+	} __attribute__((__packed__)) *attr;
+
+	unsigned int	sector_size;
+	unsigned int	cluster_size;
+	unsigned long	mft_cluster;
+	unsigned long	mft_off;
+	unsigned int	mft_record_size;
+	unsigned int	attr_type;
+	unsigned int	attr_off;
+	unsigned int	attr_len;
+	unsigned int	val_off;
+	unsigned int	val_len;
+	const __u8 *buf;
+	const __u8 *val;
 
 	ns = (struct ntfs_super_block *) get_buffer(id, 0, 0x200);
 	if (ns == NULL)
@@ -680,6 +772,78 @@
 	if (strncmp(ns->oem_id, "NTFS", 4) != 0)
 		return -1;
 
+	sector_size = le16_to_cpu(ns->bpb.bytes_per_sector);
+	cluster_size = ns->bpb.sectors_per_cluster * sector_size;
+	mft_cluster = le64_to_cpu(ns->mft_cluster_location);
+	mft_off = mft_cluster * cluster_size;
+
+	if (ns->cluster_per_mft_record < 0)
+		/* size = -log2(mft_record_size); normally 1024 Bytes */
+		mft_record_size = 1 << -ns->cluster_per_mft_record;
+	else
+		mft_record_size = ns->cluster_per_mft_record * cluster_size;
+
+	dbg("sectorsize  0x%x", sector_size);
+	dbg("clustersize 0x%x", cluster_size);
+	dbg("mftcluster  %li", mft_cluster);
+	dbg("mftoffset  0x%lx", mft_off);
+	dbg("cluster per mft_record  %i", ns->cluster_per_mft_record);
+	dbg("mft record size  %i", mft_record_size);
+
+	buf = get_buffer(id, mft_off + (MFT_RECORD_VOLUME * mft_record_size),
+			 mft_record_size);
+	if (buf == NULL)
+		goto found;
+
+	mftr = (struct master_file_table_record*) buf;
+
+	dbg("mftr->magic[0] = '%c' %03d, 0x%02x", mftr->magic[0], mftr->magic[0], mftr->magic[0]);
+	dbg("mftr->magic[1] = '%c' %03d, 0x%02x", mftr->magic[1], mftr->magic[1], mftr->magic[1]);
+	dbg("mftr->magic[2] = '%c' %03d, 0x%02x", mftr->magic[2], mftr->magic[2], mftr->magic[2]);
+	dbg("mftr->magic[3] = '%c' %03d, 0x%02x", mftr->magic[3], mftr->magic[3], mftr->magic[3]);
+	if (strncmp(mftr->magic, "FILE", 4) != 0)
+		goto found;
+
+	attr_off = le16_to_cpu(mftr->attrs_offset);
+	dbg("file $Volume's attributes are at offset %i", attr_off);
+
+	while (1) {
+		attr = (struct file_attribute*) &buf[attr_off];
+		attr_type = le32_to_cpu(attr->type);
+		attr_len = le16_to_cpu(attr->len);
+		val_off = le16_to_cpu(attr->value_offset);
+		val_len = le32_to_cpu(attr->value_len);
+
+		if (attr_type == MFT_RECORD_ATTR_END)
+			break;
+
+		dbg("found attribute type 0x%x, len %i, at offset %i",
+		    attr_type, attr_len, attr_off);
+
+		if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
+			dbg("found label, len %i", val_len);
+			if (val_len > VOLUME_ID_LABEL_SIZE)
+				val_len = VOLUME_ID_LABEL_SIZE;
+
+			val = &((__u8 *) attr)[val_off];
+			set_label_raw(id, val, val_len);
+			set_label_unicode16(id, val, LE, val_len);
+		}
+
+		if (attr_type == MFT_RECORD_ATTR_OBJECT_ID) {
+			dbg("found uuid");
+			val = &((__u8 *) attr)[val_off];
+			set_uuid(id, val, 16);
+		}
+
+		if (attr_len == 0)
+			break;
+		attr_off += attr_len;
+		if (attr_off >= mft_record_size)
+			break;
+	}
+
+found:
 	id->fs_type = NTFS;
 	id->fs_name = "ntfs";
 
@@ -689,8 +853,8 @@
 #define LARGEST_PAGESIZE			0x4000
 static int probe_swap(struct volume_id *id)
 {
-	char *sig;
-	size_t page;
+	const __u8 *sig;
+	unsigned int page;
 
 	/* huhh, the swap signature is on the end of the PAGE_SIZE */
 	for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
@@ -836,7 +1000,7 @@
 struct volume_id *volume_id_open_dev_t(dev_t devt)
 {
 	struct volume_id *id;
-	char tmp_node[VOLUME_ID_PATH_MAX];
+	__u8 tmp_node[VOLUME_ID_PATH_MAX];
 
 	snprintf(tmp_node, VOLUME_ID_PATH_MAX,
 		 "/tmp/volume-%u-%u-%u", getpid(), major(devt), minor(devt));
===== extras/volume_id/volume_id.h 1.2 vs edited =====
--- 1.2/extras/volume_id/volume_id.h	2004-05-05 01:56:47 +02:00
+++ edited/extras/volume_id/volume_id.h	2004-06-24 02:25:42 +02:00
@@ -21,9 +21,9 @@
 #ifndef _VOLUME_ID_H_
 #define _VOLUME_ID_H_
 
-#define VOLUME_ID_VERSION		002
+#define VOLUME_ID_VERSION		004
 
-#define VOLUME_ID_LABEL_SIZE		32
+#define VOLUME_ID_LABEL_SIZE		64
 #define VOLUME_ID_UUID_SIZE		16
 #define VOLUME_ID_UUID_STRING_SIZE	37
 #define VOLUME_ID_PATH_MAX		255
@@ -45,19 +45,19 @@
 };
 
 struct volume_id {
-	char		label_raw[VOLUME_ID_LABEL_SIZE];
-	size_t		label_raw_len;
+	unsigned char	label_raw[VOLUME_ID_LABEL_SIZE];
+	unsigned int	label_raw_len;
 	char		label_string[VOLUME_ID_LABEL_SIZE+1];
 	unsigned char	uuid[VOLUME_ID_UUID_SIZE];
 	char		uuid_string[VOLUME_ID_UUID_STRING_SIZE];
 	enum		filesystem_type fs_type;
 	char		*fs_name;
 	int		fd;
-	char		*sbbuf;
-	size_t		sbbuf_len;
-	char		*seekbuf;
-	size_t		seekbuf_off;
-	size_t		seekbuf_len;
+	unsigned char	*sbbuf;
+	unsigned int	sbbuf_len;
+	unsigned char	*seekbuf;
+	unsigned int	seekbuf_off;
+	unsigned int	seekbuf_len;
 	int		fd_close;
 };
 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] update udev_volume_id
  2004-06-24  0:44 [PATCH] " Kay Sievers
@ 2004-06-26  0:29 ` Greg KH
  0 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2004-06-26  0:29 UTC (permalink / raw)
  To: linux-hotplug

On Thu, Jun 24, 2004 at 02:44:11AM +0200, Kay Sievers wrote:
> Hey, seems its's update time for the tools in the extras/ folder these
> days, so I will not stand behind :)
> 
> volume_id is now able to read NTFS labels. Not very exciting, but we
> keep up to date with the version in HAL. Also __packed__ was needed for
> the structs, cause the gcc 3.4 compiled version was no longer working
> properly.

Applied, thanks.

greg k-h


-------------------------------------------------------
This SF.Net email sponsored by Black Hat Briefings & Training.
Attend Black Hat Briefings & Training, Las Vegas July 24-29 - 
digital self defense, top technical experts, no vendor pitches, 
unmatched networking opportunities. Visit www.blackhat.com
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [patch] update udev_volume_id
@ 2004-08-30  0:18 Kay Sievers
  0 siblings, 0 replies; 4+ messages in thread
From: Kay Sievers @ 2004-08-30  0:18 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 813 bytes --]

Here is an update for the volume_id callout to catch up to the latest
and greatest:

o It is able to skip the label reading of linux raid members, which are
  otherwise recognized as a normal filesystem.

o It reads FAT labels stored in the directory instead of the
  superblock (Windows only writes in the directory).

o The NTFS uuid is the right one now.

o It reads all the Apple HFS(+) formats with the labels.

o UFS volumes are recognized but no labels are extracted.

o We use CFLAGS+=-D_FILE_OFFSET_BITS=64 instead of lsee64() which may fix
  a bug mentioned on the klibc mailing list.

A lot of other new features are only used in HAL and not needed in this
simple callout. But if someone stumbles over it and want's to send a patch
for some exotic formats, we better keep it up to date :)

Thanks,
Kay

[-- Attachment #2: udev-volume_id-01.patch --]
[-- Type: text/plain, Size: 59575 bytes --]

===== extras/volume_id/Makefile 1.2 vs edited =====
--- 1.2/extras/volume_id/Makefile	2004-05-08 22:43:17 +02:00
+++ edited/extras/volume_id/Makefile	2004-07-29 04:23:37 +02:00
@@ -28,7 +28,11 @@ INSTALL_PROGRAM = ${INSTALL}
 INSTALL_DATA  = ${INSTALL} -m 644
 INSTALL_SCRIPT = ${INSTALL_PROGRAM}
 
-override CFLAGS+=-Wall -fno-builtin
+override CFLAGS+=-Wall -fno-builtin -Wchar-subscripts -Wmissing-declarations \
+		 -Wnested-externs -Wpointer-arith -Wcast-align \
+		 -Wsign-compare
+
+override CFLAGS+=-D_FILE_OFFSET_BITS=64
 
 SYSFS =	../../libsysfs/sysfs_bus.o	\
 	../../libsysfs/sysfs_class.o	\
===== extras/volume_id/udev_volume_id.c 1.2 vs edited =====
--- 1.2/extras/volume_id/udev_volume_id.c	2004-05-08 22:43:17 +02:00
+++ edited/extras/volume_id/udev_volume_id.c	2004-08-30 01:48:06 +02:00
@@ -25,6 +25,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
 
 #include "../../libsysfs/sysfs/libsysfs.h"
 #include "../../udev_lib.h"
@@ -71,6 +73,36 @@ static struct volume_id *open_classdev(s
 	return vid;
 }
 
+static unsigned long long get_size(struct volume_id *vid)
+{
+	unsigned long long size;
+
+	if (ioctl(vid->fd, BLKGETSIZE64, &size) != 0)
+		size = 0;
+
+	return size;
+}
+
+static char *usage_id_name(enum volume_id_usage usage)
+{
+	switch(usage) {
+	case VOLUME_ID_UNUSED:
+		return "unused";
+	case VOLUME_ID_UNPROBED:
+		return "unprobed";
+	case VOLUME_ID_OTHER:
+		return "other";
+	case VOLUME_ID_PARTITIONTABLE:
+		return "partitiontable";
+	case VOLUME_ID_FILESYSTEM:
+		return "filesystem";
+	case VOLUME_ID_RAID:
+		return "raid";
+	default:
+		return "unknown type_id";
+	}
+}
+
 int main(int argc, char *argv[])
 {
 	const char help[] = "usage: udev_volume_id [-t|-l|-u|-d]\n"
@@ -80,7 +112,6 @@ int main(int argc, char *argv[])
 			    "       -d disk label from main device\n"
 			    "\n";
 	static const char short_options[] = "htlud";
-	int option;
 	char sysfs_path[SYSFS_PATH_MAX];
 	char dev_path[SYSFS_PATH_MAX];
 	struct sysfs_class_device *class_dev = NULL;
@@ -92,9 +123,12 @@ int main(int argc, char *argv[])
 	char dasd_label[7];
 	static char name[VOLUME_ID_LABEL_SIZE];
 	int len, i, j;
+	unsigned long long size;
 	int rc = 1;
 
 	while (1) {
+		int option;
+
 		option = getopt(argc, argv, short_options);
 		if (option == -1)
 			break;
@@ -146,24 +180,26 @@ int main(int argc, char *argv[])
 		vid = open_classdev(class_dev);
 		if (vid == NULL)
 			goto exit;
-		if (volume_id_probe(vid, ALL) == 0)
+
+		size = get_size(vid);
+
+		if (volume_id_probe(vid, VOLUME_ID_ALL, 0, size) == 0)
 			goto print;
 		break;
 	case 'd' :
-		/* if we are on a partition, close it and open main block device */
+		/* if we are on a partition, open main block device instead */
 		class_dev_parent = sysfs_get_classdev_parent(class_dev);
-		if (class_dev_parent != NULL) {
-			volume_id_close(vid);
+		if (class_dev_parent != NULL)
 			vid = open_classdev(class_dev_parent);
-		} else {
+		else
 			vid = open_classdev(class_dev_parent);
-		}
 		if (vid == NULL)
 			goto exit;
+
 		if (probe_ibm_partition(vid->fd, dasd_label) == 0) {
-			vid->fs_name = "dasd";
-			strncpy(vid->label_string, dasd_label, 6);
-			vid->label_string[6] = '\0';
+			vid->type = "dasd";
+			strncpy(vid->label, dasd_label, 6);
+			vid->label[6] = '\0';
 			goto print;
 		}
 		break;
@@ -174,10 +210,10 @@ int main(int argc, char *argv[])
 
 
 print:
-	len = strnlen(vid->label_string, VOLUME_ID_LABEL_SIZE);
+	len = strnlen(vid->label, VOLUME_ID_LABEL_SIZE);
 
 	/* remove trailing spaces */
-	while (len > 0 && isspace(vid->label_string[len-1]))
+	while (len > 0 && isspace(vid->label[len-1]))
 		len--;
 	name[len] = '\0';
 
@@ -185,14 +221,14 @@ print:
 	i = 0;
 	j = 0;
 	while (j < len) {
-		switch(vid->label_string[j]) {
+		switch(vid->label[j]) {
 		case '/' :
 			break;
 		case ' ' :
 			name[i++] = '_';
 			break;
 		default :
-			name[i++] = vid->label_string[j];
+			name[i++] = vid->label[j];
 		}
 		j++;
 	}
@@ -200,27 +236,29 @@ print:
 
 	switch (print) {
 	case 't':
-		printf("%s\n", vid->fs_name);
+		printf("%s\n", vid->type);
 		break;
 	case 'l':
-		if (name[0] == '\0') {
+		if (name[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
 			rc = 2;
 			goto exit;
 		}
 		printf("%s\n", name);
 		break;
 	case 'u':
-		if (vid->uuid_string[0] == '\0') {
+		if (vid->uuid[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
 			rc = 2;
 			goto exit;
 		}
-		printf("%s\n", vid->uuid_string);
+		printf("%s\n", vid->uuid);
 		break;
 	case 'a':
-		printf("T:%s\n", vid->fs_name);
-		printf("L:%s\n", vid->label_string);
+		printf("F:%s\n", usage_id_name(vid->usage_id));
+		printf("T:%s\n", vid->type);
+		printf("V:%s\n", vid->type_version);
+		printf("L:%s\n", vid->label);
 		printf("N:%s\n", name);
-		printf("U:%s\n", vid->uuid_string);
+		printf("U:%s\n", vid->uuid);
 	}
 	rc = 0;
 
===== extras/volume_id/volume_id.c 1.4 vs edited =====
--- 1.4/extras/volume_id/volume_id.c	2004-06-24 02:25:42 +02:00
+++ edited/extras/volume_id/volume_id.c	2004-08-30 01:12:28 +02:00
@@ -3,13 +3,10 @@
  *
  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
- *	The superblock structs are taken from the libblkid living inside
- *	the e2fsprogs. This is a simple straightforward implementation for
- *	reading the label strings of only the most common filesystems.
- *	If you need a full featured library with attribute caching, support for
- *	much more partition/media types or non-root disk access, you may have
- *	a look at:
- *		http://e2fsprogs.sourceforge.net.
+ *	The superblock structs are taken from the linux kernel sources
+ *	and the libblkid living inside the e2fsprogs. This is a simple
+ *	straightforward implementation for reading the label strings of the
+ *	most common filesystems.
  *
  *	This library is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU Lesser General Public
@@ -30,6 +27,10 @@
 #define _GNU_SOURCE
 #endif
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -49,7 +50,7 @@
 	} while (0)
 #else
 #define dbg(format, arg...)	do {} while (0)
-#endif
+#endif /* DEBUG */
 
 #define bswap16(x) (__u16)((((__u16)(x) & 0x00ffu) << 8) | \
 			   (((__u32)(x) & 0xff00u) >> 8))
@@ -68,20 +69,24 @@
 			   (((__u64)(x) & 0x000000000000ff00u) << 40) | \
 			   (((__u64)(x) & 0x00000000000000ffu) << 56))
 
-#if (__BYTE_ORDER == __LITTLE_ENDIAN) 
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
 #define le16_to_cpu(x) (x)
 #define le32_to_cpu(x) (x)
 #define le64_to_cpu(x) (x)
+#define be16_to_cpu(x) bswap16(x)
+#define be32_to_cpu(x) bswap32(x)
 #elif (__BYTE_ORDER == __BIG_ENDIAN)
 #define le16_to_cpu(x) bswap16(x)
 #define le32_to_cpu(x) bswap32(x)
 #define le64_to_cpu(x) bswap64(x)
+#define be16_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
 #endif
 
-/* size of superblock buffer, reiser block is at 64k */
+/* size of superblock buffer, reiserfs block is at 64k */
 #define SB_BUFFER_SIZE				0x11000
-/* size of seek buffer 2k */
-#define SEEK_BUFFER_SIZE			0x800
+/* size of seek buffer 4k */
+#define SEEK_BUFFER_SIZE			0x1000
 
 
 static void set_label_raw(struct volume_id *id,
@@ -96,15 +101,15 @@ static void set_label_string(struct volu
 {
 	unsigned int i;
 
-	memcpy(id->label_string, buf, count);
+	memcpy(id->label, buf, count);
 
 	/* remove trailing whitespace */
-	i = strnlen(id->label_string, count);
+	i = strnlen(id->label, count);
 	while (i--) {
-		if (! isspace(id->label_string[i]))
+		if (! isspace(id->label[i]))
 			break;
 	}
-	id->label_string[i+1] = '\0';
+	id->label[i+1] = '\0';
 }
 
 #define LE		0
@@ -118,23 +123,23 @@ static void set_label_unicode16(struct v
 	__u16 c;
 
 	j = 0;
-	for (i = 0; i <= count-2; i += 2) {
+	for (i = 0; i + 2 <= count; i += 2) {
 		if (endianess == LE)
 			c = (buf[i+1] << 8) | buf[i];
 		else
 			c = (buf[i] << 8) | buf[i+1];
 		if (c == 0) {
-			id->label_string[j] = '\0';
+			id->label[j] = '\0';
 			break;
 		} else if (c < 0x80) {
-			id->label_string[j++] = (__u8) c;
+			id->label[j++] = (__u8) c;
 		} else if (c < 0x800) {
-			id->label_string[j++] = (__u8) (0xc0 | (c >> 6));
-			id->label_string[j++] = (__u8) (0x80 | (c & 0x3f));
+			id->label[j++] = (__u8) (0xc0 | (c >> 6));
+			id->label[j++] = (__u8) (0x80 | (c & 0x3f));
 		} else {
-			id->label_string[j++] = (__u8) (0xe0 | (c >> 12));
-			id->label_string[j++] = (__u8) (0x80 | ((c >> 6) & 0x3f));
-			id->label_string[j++] = (__u8) (0x80 | (c & 0x3f));
+			id->label[j++] = (__u8) (0xe0 | (c >> 12));
+			id->label[j++] = (__u8) (0x80 | ((c >> 6) & 0x3f));
+			id->label[j++] = (__u8) (0x80 | (c & 0x3f));
 		}
 	}
 }
@@ -144,10 +149,10 @@ static void set_uuid(struct volume_id *i
 {
 	unsigned int i;
 
-	memcpy(id->uuid, buf, count);
+	memcpy(id->uuid_raw, buf, count);
 
 	/* create string if uuid is set */
-	for (i = 0; i < count; i++) 
+	for (i = 0; i < count; i++)
 		if (buf[i] != 0)
 			goto set;
 	return;
@@ -155,11 +160,16 @@ static void set_uuid(struct volume_id *i
 set:
 	switch(count) {
 	case 4:
-		sprintf(id->uuid_string, "%02X%02X-%02X%02X",
+		sprintf(id->uuid, "%02X%02X-%02X%02X",
+			buf[3], buf[2], buf[1], buf[0]);
+		break;
+	case 8:
+		sprintf(id->uuid,"%02X%02X-%02X%02X-%02X%02X-%02X%02X",
+			buf[7], buf[6], buf[5], buf[4],
 			buf[3], buf[2], buf[1], buf[0]);
 		break;
 	case 16:
-		sprintf(id->uuid_string,
+		sprintf(id->uuid,
 			"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
 			"%02x%02x%02x%02x%02x%02x",
 			buf[0], buf[1], buf[2], buf[3],
@@ -171,11 +181,11 @@ set:
 	}
 }
 
-static __u8 *get_buffer(struct volume_id *id,
-			unsigned long off, unsigned int len)
+static __u8 *get_buffer(struct volume_id *id, __u64 off, unsigned int len)
 {
 	unsigned int buf_len;
 
+	dbg("get buffer off 0x%llx, len 0x%x", off, len);
 	/* check if requested area fits in superblock buffer */
 	if (off + len <= SB_BUFFER_SIZE) {
 		if (id->sbbuf == NULL) {
@@ -186,9 +196,10 @@ static __u8 *get_buffer(struct volume_id
 
 		/* check if we need to read */
 		if ((off + len) > id->sbbuf_len) {
-			dbg("read sbbuf len:0x%lx", off + len);
-			lseek64(id->fd, 0, SEEK_SET);
+			dbg("read sbbuf len:0x%llx", off + len);
+			lseek(id->fd, 0, SEEK_SET);
 			buf_len = read(id->fd, id->sbbuf, off + len);
+			dbg("got 0x%x (%i) bytes", buf_len, buf_len);
 			id->sbbuf_len = buf_len;
 			if (buf_len < off + len)
 				return NULL;
@@ -209,8 +220,9 @@ static __u8 *get_buffer(struct volume_id
 		/* check if we need to read */
 		if ((off < id->seekbuf_off) ||
 		    ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
-			dbg("read seekbuf off:0x%lx len:0x%x", off, len);
-			lseek64(id->fd, off, SEEK_SET);
+			dbg("read seekbuf off:0x%llx len:0x%x", off, len);
+			if (lseek(id->fd, off, SEEK_SET) == -1)
+				return NULL;
 			buf_len = read(id->fd, id->seekbuf, len);
 			dbg("got 0x%x (%i) bytes", buf_len, buf_len);
 			id->seekbuf_off = off;
@@ -237,10 +249,298 @@ static void free_buffer(struct volume_id
 	}
 }
 
+#define LVM1_SB_OFF			0x400
+#define LVM1_MAGIC			"HM"
+static int probe_lvm1(struct volume_id *id, __u64 off)
+{
+	struct lvm2_super_block {
+		__u8	id[2];
+	} __attribute__((packed)) *lvm;
+
+	const __u8 *buf;
+
+	buf = get_buffer(id, off + LVM1_SB_OFF, 0x800);
+	if (buf == NULL)
+		return -1;
+
+	lvm = (struct lvm2_super_block *) buf;
+
+	if (strncmp(lvm->id, LVM1_MAGIC, 2) != 0)
+		return -1;
+
+	id->usage_id = VOLUME_ID_RAID;
+	id->type_id = VOLUME_ID_LVM1;
+	id->type = "LVM1_member";
+
+	return 0;
+}
+
+#define LVM2_LABEL_ID			"LABELONE"
+#define LVM2LABEL_SCAN_SECTORS		4
+static int probe_lvm2(struct volume_id *id, __u64 off)
+{
+	struct lvm2_super_block {
+		__u8	id[8];
+		__u64	sector_xl;
+		__u32	crc_xl;
+		__u32	offset_xl;
+		__u8	type[8];
+	} __attribute__((packed)) *lvm;
+
+	const __u8 *buf;
+	unsigned int soff;
+
+	buf = get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
+	if (buf == NULL)
+		return -1;
+
+
+	for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
+		lvm = (struct lvm2_super_block *) &buf[soff];
+
+		if (strncmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
+			goto found;
+	}
+
+	return -1;
+
+found:
+	strncpy(id->type_version, lvm->type, 8);
+	id->usage_id = VOLUME_ID_RAID;
+	id->type_id = VOLUME_ID_LVM1;
+	id->type = "LVM2_member";
+
+	return 0;
+}
+
+#define MD_RESERVED_BYTES		0x10000
+#define MD_MAGIC			0xa92b4efc
+static int probe_linux_raid(struct volume_id *id, __u64 off, __u64 size)
+{
+	struct mdp_super_block {
+		__u32	md_magic;
+		__u32	major_version;
+		__u32	minor_version;
+		__u32	patch_version;
+		__u32	gvalid_words;
+		__u32	set_uuid0;
+		__u32	ctime;
+		__u32	level;
+		__u32	size;
+		__u32	nr_disks;
+		__u32	raid_disks;
+		__u32	md_minor;
+		__u32	not_persistent;
+		__u32	set_uuid1;
+		__u32	set_uuid2;
+		__u32	set_uuid3;
+	} __attribute__((packed)) *mdp;
+
+	const __u8 *buf;
+	__u64 sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
+	__u8 uuid[16];
+
+	if (size < 0x10000)
+		return -1;
+
+	buf = get_buffer(id, off + sboff, 0x800);
+	if (buf == NULL)
+		return -1;
+
+	mdp = (struct mdp_super_block *) buf;
+
+	if (le32_to_cpu(mdp->md_magic) != MD_MAGIC)
+		return -1;
+
+	memcpy(uuid, &mdp->set_uuid0, 4);
+	memcpy(&uuid[4], &mdp->set_uuid1, 12);
+	set_uuid(id, uuid, 16);
+
+	snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1, "%u.%u.%u",
+		 le32_to_cpu(mdp->major_version),
+		 le32_to_cpu(mdp->minor_version),
+		 le32_to_cpu(mdp->patch_version));
+
+	dbg("found raid signature");
+	id->usage_id = VOLUME_ID_RAID;
+	id->type = "linux_raid_member";
+
+	return 0;
+}
+
+#define MSDOS_MAGIC			"\x55\xaa"
+#define MSDOS_PARTTABLE_OFFSET		0x1be
+#define MSDOS_SIG_OFF			0x1fe
+#define BSIZE				0x200
+#define DOS_EXTENDED_PARTITION		0x05
+#define LINUX_EXTENDED_PARTITION	0x85
+#define WIN98_EXTENDED_PARTITION	0x0f
+#define LINUX_RAID_PARTITION		0xfd
+#define is_extended(type) \
+	(type == DOS_EXTENDED_PARTITION ||	\
+	 type == WIN98_EXTENDED_PARTITION ||	\
+	 type == LINUX_EXTENDED_PARTITION)
+#define is_raid(type) \
+	(type == LINUX_RAID_PARTITION)
+static int probe_msdos_part_table(struct volume_id *id, __u64 off)
+{
+	struct msdos_partition_entry {
+		__u8	boot_ind;
+		__u8	head;
+		__u8	sector;
+		__u8	cyl;
+		__u8	sys_ind;
+		__u8	end_head;
+		__u8	end_sector;
+		__u8	end_cyl;
+		__u32	start_sect;
+		__u32	nr_sects;
+	} __attribute__((packed)) *part;
+
+	const __u8 *buf;
+	int i;
+	__u64 poff;
+	__u64 plen;
+	__u64 extended = 0;
+	__u64 current;
+	__u64 next;
+	int limit;
+	int empty = 1;
+	struct volume_id_partition *p;
+
+	buf = get_buffer(id, off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
+		return -1;
+
+	/* check flags on all entries for a valid partition table */
+	part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
+	for (i = 0; i < 4; i++) {
+		if (part[i].boot_ind != 0 &&
+		    part[i].boot_ind != 0x80)
+			return -1;
+
+		if (le32_to_cpu(part[i].nr_sects) != 0)
+			empty = 0;
+	}
+	if (empty == 1)
+		return -1;
+
+	if (id->partitions != NULL)
+		free(id->partitions);
+	id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX *
+				sizeof(struct volume_id_partition));
+	if (id->partitions == NULL)
+		return -1;
+	memset(id->partitions, 0x00,
+	       VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition));
+
+	for (i = 0; i < 4; i++) {
+		poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
+		plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
+
+		if (plen == 0)
+			continue;
+
+		p = &id->partitions[i];
+
+		if (is_extended(part[i].sys_ind)) {
+			dbg("found extended partition at 0x%llx", poff);
+			p->usage_id = VOLUME_ID_PARTITIONTABLE;
+			p->type_id = VOLUME_ID_MSDOSEXTENDED;
+			p->type = "msdos_extended_partition";
+			if (extended == 0)
+				extended = off + poff;
+		} else {
+			dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
+			    part[i].sys_ind, poff, plen);
+
+			if (is_raid(part[i].sys_ind))
+				p->usage_id = VOLUME_ID_RAID;
+			else
+				p->usage_id = VOLUME_ID_UNPROBED;
+		}
+
+		p->off = off + poff;
+		p->len = plen;
+		id->partition_count = i+1;
+	}
+
+	next = extended;
+	current = extended;
+	limit = 50;
+
+	/* follow extended partition chain and add data partitions */
+	while (next != 0) {
+		if (limit-- == 0) {
+			dbg("extended chain limit reached");
+			break;
+		}
+
+		buf = get_buffer(id, current, 0x200);
+		if (buf == NULL)
+			break;
+
+		part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
+
+		if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
+			break;
+
+		next = 0;
+
+		for (i = 0; i < 4; i++) {
+			poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
+			plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
+
+			if (plen == 0)
+				continue;
+
+			if (is_extended(part[i].sys_ind)) {
+				dbg("found extended partition at 0x%llx", poff);
+				if (next == 0)
+					next = extended + poff;
+			} else {
+				dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
+					part[i].sys_ind, poff, plen);
+
+				/* we always start at the 5th entry */
+				while (id->partition_count < 4)
+					id->partitions[id->partition_count++].usage_id =
+						VOLUME_ID_UNUSED;
+
+				p = &id->partitions[id->partition_count];
+
+				if (is_raid(part[i].sys_ind))
+					p->usage_id = VOLUME_ID_RAID;
+				else
+					p->usage_id = VOLUME_ID_UNPROBED;
+
+				p->off = current + poff;
+				p->len = plen;
+				id->partition_count++;
+				if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
+					dbg("to many partitions");
+					next = 0;
+				}
+			}
+		}
+
+		current = next;
+	}
+
+	id->usage_id = VOLUME_ID_PARTITIONTABLE;
+	id->type_id = VOLUME_ID_MSDOSPARTTABLE;
+	id->type = "msdos_partition_table";
+
+	return 0;
+}
+
 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x00000004
 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x00000008
 #define EXT_SUPERBLOCK_OFFSET			0x400
-static int probe_ext(struct volume_id *id)
+static int probe_ext(struct volume_id *id, __u64 off)
 {
 	struct ext2_super_block {
 		__u32	inodes_count;
@@ -262,7 +562,7 @@ static int probe_ext(struct volume_id *i
 	} __attribute__((__packed__)) *es;
 
 	es = (struct ext2_super_block *)
-	     get_buffer(id, EXT_SUPERBLOCK_OFFSET, 0x200);
+	     get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
 	if (es == NULL)
 		return -1;
 
@@ -276,21 +576,23 @@ static int probe_ext(struct volume_id *i
 
 	if ((le32_to_cpu(es->feature_compat) &
 	     EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
-		id->fs_type = EXT3;
-		id->fs_name = "ext3";
+		id->usage_id = VOLUME_ID_FILESYSTEM;
+		id->type_id = VOLUME_ID_EXT3;
+		id->type = "ext3";
 	} else {
-		id->fs_type = EXT2;
-		id->fs_name = "ext2";
+		id->usage_id = VOLUME_ID_FILESYSTEM;
+		id->type_id = VOLUME_ID_EXT2;
+		id->type = "ext2";
 	}
 
 	return 0;
 }
 
-#define REISER1_SUPERBLOCK_OFFSET		0x2000
-#define REISER_SUPERBLOCK_OFFSET		0x10000
-static int probe_reiser(struct volume_id *id)
+#define REISERFS1_SUPERBLOCK_OFFSET		0x2000
+#define REISERFS_SUPERBLOCK_OFFSET		0x10000
+static int probe_reiserfs(struct volume_id *id, __u64 off)
 {
-	struct reiser_super_block {
+	struct reiserfs_super_block {
 		__u32	blocks_count;
 		__u32	free_blocks;
 		__u32	root_block;
@@ -306,23 +608,30 @@ static int probe_reiser(struct volume_id
 		__u8	label[16];
 	} __attribute__((__packed__)) *rs;
 
-	rs = (struct reiser_super_block *)
-	     get_buffer(id, REISER_SUPERBLOCK_OFFSET, 0x200);
+	rs = (struct reiserfs_super_block *)
+	     get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
 	if (rs == NULL)
 		return -1;
 
-	if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0)
+	if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0) {
+		strcpy(id->type_version, "3.6");
 		goto found;
-	if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0)
+	}
+
+	if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0) {
+		strcpy(id->type_version, "JR");
 		goto found;
+	}
 
-	rs = (struct reiser_super_block *)
-	     get_buffer(id, REISER1_SUPERBLOCK_OFFSET, 0x200);
+	rs = (struct reiserfs_super_block *)
+	     get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
 	if (rs == NULL)
 		return -1;
 
-	if (strncmp(rs->magic, "ReIsErFs", 8) == 0)
+	if (strncmp(rs->magic, "ReIsErFs", 8) == 0) {
+		strcpy(id->type_version, "3.5");
 		goto found;
+	}
 
 	return -1;
 
@@ -331,13 +640,14 @@ found:
 	set_label_string(id, rs->label, 16);
 	set_uuid(id, rs->uuid, 16);
 
-	id->fs_type = REISER;
-	id->fs_name = "reiser";
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_REISERFS;
+	id->type = "reiserfs";
 
 	return 0;
 }
 
-static int probe_xfs(struct volume_id *id)
+static int probe_xfs(struct volume_id *id, __u64 off)
 {
 	struct xfs_super_block {
 		__u8	magic[4];
@@ -354,7 +664,7 @@ static int probe_xfs(struct volume_id *i
 		__u64	fdblocks;
 	} __attribute__((__packed__)) *xs;
 
-	xs = (struct xfs_super_block *) get_buffer(id, 0, 0x200);
+	xs = (struct xfs_super_block *) get_buffer(id, off, 0x200);
 	if (xs == NULL)
 		return -1;
 
@@ -365,14 +675,15 @@ static int probe_xfs(struct volume_id *i
 	set_label_string(id, xs->fname, 12);
 	set_uuid(id, xs->uuid, 16);
 
-	id->fs_type = XFS;
-	id->fs_name = "xfs";
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_XFS;
+	id->type = "xfs";
 
 	return 0;
 }
 
 #define JFS_SUPERBLOCK_OFFSET			0x8000
-static int probe_jfs(struct volume_id *id)
+static int probe_jfs(struct volume_id *id, __u64 off)
 {
 	struct jfs_super_block {
 		__u8	magic[4];
@@ -388,7 +699,7 @@ static int probe_jfs(struct volume_id *i
 	} __attribute__((__packed__)) *js;
 
 	js = (struct jfs_super_block *)
-	     get_buffer(id, JFS_SUPERBLOCK_OFFSET, 0x200);
+	     get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
 	if (js == NULL)
 		return -1;
 
@@ -399,115 +710,294 @@ static int probe_jfs(struct volume_id *i
 	set_label_string(id, js->label, 16);
 	set_uuid(id, js->uuid, 16);
 
-	id->fs_type = JFS;
-	id->fs_name = "jfs";
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_JFS;
+	id->type = "jfs";
 
 	return 0;
 }
 
-static int probe_vfat(struct volume_id *id)
+#define FAT12_MAX			0xff5
+#define FAT16_MAX			0xfff5
+#define FAT_ATTR_VOLUME			0x08
+struct vfat_dir_entry {
+	__u8	name[11];
+	__u8	attr;
+	__u16	time_creat;
+	__u16	date_creat;
+	__u16	time_acc;
+	__u16	date_acc;
+	__u16	cluster_high;
+	__u16	time_write;
+	__u16	date_write;
+	__u16	cluster_low;
+	__u32	size;
+} __attribute__((__packed__));
+
+static  char *vfat_search_label_in_dir(const __u8 *buf, __u16 size)
+{
+	struct vfat_dir_entry *dir;
+	int i;
+	__u16 count;
+
+	dir = (struct vfat_dir_entry*) buf;
+	count = size / sizeof(struct vfat_dir_entry);
+	dbg("expected entries 0x%x", count);
+
+	for (i = 0; i <= count; i++) {
+		/* end marker */
+		if (dir[i].attr == 0x00) {
+			dbg("end of dir");
+			return NULL;
+		}
+
+		/* empty entry */
+		if (dir[i].attr == 0xe5)
+			continue;
+
+		if (dir[i].attr == FAT_ATTR_VOLUME) {
+			dbg("found ATTR_VOLUME id in root dir");
+			return dir[i].name;
+		}
+
+		dbg("skip dir entry");
+	}
+
+	return NULL;
+}
+
+static int probe_vfat(struct volume_id *id, __u64 off)
 {
 	struct vfat_super_block {
-		__u8	ignored[3];
+		__u8	boot_jump[3];
 		__u8	sysid[8];
-		__u8	sector_size[2];
-		__u8	cluster_size;
+		__u16	sector_size;
+		__u8	sectors_per_cluster;
 		__u16	reserved;
 		__u8	fats;
-		__u8	dir_entries[2];
-		__u8	sectors[2];
+		__u16	dir_entries;
+		__u16	sectors;
 		__u8	media;
 		__u16	fat_length;
 		__u16	secs_track;
 		__u16	heads;
 		__u32	hidden;
 		__u32	total_sect;
-		__u32	fat32_length;
-		__u16	flags;
-		__u8	version[2];
-		__u32	root_cluster;
-		__u16	insfo_sector;
-		__u16	backup_boot;
-		__u16	reserved2[6];
-		__u8	unknown[3];
-		__u8	serno[4];
-		__u8	label[11];
-		__u8	magic[8];
-		__u8	dummy2[164];
-		__u8	pmagic[2];
+		union {
+			struct fat_super_block {
+				__u8	unknown[3];
+				__u8	serno[4];
+				__u8	label[11];
+				__u8	magic[8];
+				__u8	dummy2[192];
+				__u8	pmagic[2];
+			} __attribute__((__packed__)) fat;
+			struct fat32_super_block {
+				__u32	fat32_length;
+				__u16	flags;
+				__u8	version[2];
+				__u32	root_cluster;
+				__u16	insfo_sector;
+				__u16	backup_boot;
+				__u16	reserved2[6];
+				__u8	unknown[3];
+				__u8	serno[4];
+				__u8	label[11];
+				__u8	magic[8];
+				__u8	dummy2[164];
+				__u8	pmagic[2];
+			} __attribute__((__packed__)) fat32;
+		} __attribute__((__packed__)) type;
 	} __attribute__((__packed__)) *vs;
 
-	vs = (struct vfat_super_block *) get_buffer(id, 0, 0x200);
+	__u16 sector_size;
+	__u16 dir_entries;
+	__u32 sect_count;
+	__u16 reserved;
+	__u16 fat_size;
+	__u32 root_cluster;
+	__u32 dir_size;
+	__u32 cluster_count;
+	__u32 fat_length;
+	__u64 root_start;
+	__u32 start_data_sect;
+	__u16 root_dir_entries;
+	__u8 *buf;
+	__u32 buf_size;
+	__u8 *label = NULL;
+	__u32 next;
+
+	vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
 	if (vs == NULL)
 		return -1;
 
-	if (strncmp(vs->magic, "MSWIN", 5) == 0)
-		goto found;
-	if (strncmp(vs->magic, "FAT32   ", 8) == 0)
-		goto found;
-	return -1;
+	/* believe only that's fat, don't trust the version
+	 * the cluster_count will tell us
+	 */
+	if (strncmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
+		goto valid;
+
+	if (strncmp(vs->type.fat32.magic, "FAT32   ", 8) == 0)
+		goto valid;
+
+	if (strncmp(vs->type.fat.magic, "FAT16   ", 8) == 0)
+		goto valid;
+
+	if (strncmp(vs->type.fat.magic, "MSDOS", 5) == 0)
+		goto valid;
+
+	if (strncmp(vs->type.fat.magic, "FAT12   ", 8) == 0)
+		goto valid;
+
+	/*
+	 * There are old floppies out there without a magic, so we check
+	 * for well known values and guess if it's a fat volume
+	 */
+
+	/* boot jump address check */
+	if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
+	     vs->boot_jump[0] != 0xe9)
+		return -1;
 
-found:
-	set_label_raw(id, vs->label, 11);
-	set_label_string(id, vs->label, 11);
-	set_uuid(id, vs->serno, 4);
+	/* heads check */
+	if (vs->heads == 0)
+		return -1;
 
-	id->fs_type = VFAT;
-	id->fs_name = "vfat";
+	/* cluster size check*/	
+	if (vs->sectors_per_cluster == 0 ||
+	    (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
+		return -1;
 
-	return 0;
-}
+	/* media check */
+	if (vs->media < 0xf8 && vs->media != 0xf0)
+		return -1;
 
-static int probe_msdos(struct volume_id *id)
-{
-	struct msdos_super_block {
-		__u8	ignored[3];
-		__u8	sysid[8];
-		__u8	sector_size[2];
-		__u8	cluster_size;
-		__u16	reserved;
-		__u8	fats;
-		__u8	dir_entries[2];
-		__u8	sectors[2];
-		__u8	media;
-		__u16	fat_length;
-		__u16	secs_track;
-		__u16	heads;
-		__u32	hidden;
-		__u32	total_sect;
-		__u8	unknown[3];
-		__u8	serno[4];
-		__u8	label[11];
-		__u8	magic[8];
-		__u8	dummy2[192];
-		__u8	pmagic[2];
-	} __attribute__((__packed__)) *ms;
+	/* fat count*/
+	if (vs->fats != 2)
+		return -1;
 
-	ms = (struct msdos_super_block *) get_buffer(id, 0, 0x200);
-	if (ms == NULL)
+valid:
+	/* sector size check */
+	sector_size = le16_to_cpu(vs->sector_size);
+	if (sector_size != 0x200 && sector_size != 0x400 &&
+	    sector_size != 0x800 && sector_size != 0x1000)
 		return -1;
 
-	if (strncmp(ms->magic, "MSDOS", 5) == 0)
-		goto found;
-	if (strncmp(ms->magic, "FAT16   ", 8) == 0)
-		goto found;
-	if (strncmp(ms->magic, "FAT12   ", 8) == 0)
+	dbg("sector_size 0x%x", sector_size);
+	dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
+
+	dir_entries = le16_to_cpu(vs->dir_entries);
+	reserved = le16_to_cpu(vs->reserved);
+	dbg("reserved 0x%x", reserved);
+
+	sect_count = le16_to_cpu(vs->sectors);
+	if (sect_count == 0)
+		sect_count = vs->total_sect;
+	dbg("sect_count 0x%x", sect_count);
+
+	fat_length = le16_to_cpu(vs->fat_length);
+	if (fat_length == 0)
+		fat_length = le32_to_cpu(vs->type.fat32.fat32_length);
+	dbg("fat_length 0x%x", fat_length);
+
+	fat_size = fat_length * vs->fats;
+	dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
+			(sector_size-1)) / sector_size;
+	dbg("dir_size 0x%x", dir_size);
+
+	cluster_count = sect_count - (reserved + fat_size + dir_size);
+	cluster_count /= vs->sectors_per_cluster;
+	dbg("cluster_count 0x%x", cluster_count);
+
+	if (cluster_count < FAT12_MAX) {
+		strcpy(id->type_version, "FAT12");
+	} else if (cluster_count < FAT16_MAX) {
+		strcpy(id->type_version, "FAT16");
+	} else {
+		strcpy(id->type_version, "FAT32");
+		goto fat32;
+	}
+
+	/* the label may be an attribute in the root directory */
+	root_start = (reserved + fat_size) * sector_size;
+	root_dir_entries = le16_to_cpu(vs->dir_entries);
+	dbg("root dir start 0x%x", root_start);
+
+	buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
+	buf = get_buffer(id, off + root_start, buf_size);
+	if (buf == NULL)
 		goto found;
-	return -1;
 
-found:
-	set_label_raw(id, ms->label, 11);
-	set_label_string(id, ms->label, 11);
-	set_uuid(id, ms->serno, 4);
+	label = vfat_search_label_in_dir(buf, buf_size);
+
+	if (label != NULL && strncmp(label, "NO NAME    ", 11) != 0) {
+		set_label_raw(id, label, 11);
+		set_label_string(id, label, 11);
+	} else if (strncmp(vs->type.fat.label, "NO NAME    ", 11) != 0) {
+		set_label_raw(id, vs->type.fat.label, 11);
+		set_label_string(id, vs->type.fat.label, 11);
+	}
+	set_uuid(id, vs->type.fat.serno, 4);
+	goto found;
+
+fat32:
+	/* FAT32 root dir is a cluster chain like any other directory */
+	buf_size = vs->sectors_per_cluster * sector_size;
+	root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
+	dbg("root dir cluster %u", root_cluster);
+	start_data_sect = reserved + fat_size;
+
+	next = root_cluster;
+	while (1) {
+		__u32 next_sect_off;
+		__u64 next_off;
+		__u64 fat_entry_off;
+
+		dbg("next cluster %u", next);
+		next_sect_off = (next - 2) * vs->sectors_per_cluster;
+		next_off = (start_data_sect + next_sect_off) * sector_size;
+		dbg("cluster offset 0x%x", next_off);
+
+		/* get cluster */
+		buf = get_buffer(id, off + next_off, buf_size);
+		if (buf == NULL)
+			goto found;
+
+		label = vfat_search_label_in_dir(buf, buf_size);
+		if (label != NULL)
+			break;
+
+		/* get FAT entry */
+		fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
+		buf = get_buffer(id, off + fat_entry_off, buf_size);
+		if (buf == NULL)
+			goto found;
+
+		/* set next cluster */
+		next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
+		if (next == 0)
+			break;
+	}
+
+	if (label != NULL && strncmp(label, "NO NAME    ", 11) != 0) {
+		set_label_raw(id, label, 11);
+		set_label_string(id, label, 11);
+	} else if (strncmp(vs->type.fat32.label, "NO NAME    ", 11) == 0) {
+		set_label_raw(id, vs->type.fat32.label, 11);
+		set_label_string(id, vs->type.fat32.label, 11);
+	}
+	set_uuid(id, vs->type.fat32.serno, 4);
 
-	id->fs_type = MSDOS;
-	id->fs_name = "msdos";
+found:
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_VFAT;
+	id->type = "vfat";
 
 	return 0;
 }
 
 #define UDF_VSD_OFFSET			0x8000
-static int probe_udf(struct volume_id *id)
+static int probe_udf(struct volume_id *id, __u64 off)
 {
 	struct volume_descriptor {
 		struct descriptor_tag {
@@ -550,7 +1040,7 @@ static int probe_udf(struct volume_id *i
 	unsigned int clen;
 
 	vsd = (struct volume_structure_descriptor *)
-	      get_buffer(id, UDF_VSD_OFFSET, 0x200);
+	      get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
 	if (vsd == NULL)
 		return -1;
 
@@ -574,7 +1064,7 @@ blocksize:
 	/* search the next VSD to get the logical block size of the volume */
 	for (bs = 0x800; bs < 0x8000; bs += 0x800) {
 		vsd = (struct volume_structure_descriptor *)
-		      get_buffer(id, UDF_VSD_OFFSET + bs, 0x800);
+		      get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
 		if (vsd == NULL)
 			return -1;
 		dbg("test for blocksize: 0x%x", bs);
@@ -587,7 +1077,7 @@ nsr:
 	/* search the list of VSDs for a NSR descriptor */
 	for (b = 0; b < 64; b++) {
 		vsd = (struct volume_structure_descriptor *)
-		      get_buffer(id, UDF_VSD_OFFSET + (b * bs), 0x800);
+		      get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
 		if (vsd == NULL)
 			return -1;
 
@@ -605,7 +1095,8 @@ nsr:
 
 anchor:
 	/* read anchor volume descriptor */
-	vd = (struct volume_descriptor *) get_buffer(id, 256 * bs, 0x200);
+	vd = (struct volume_descriptor *)
+		get_buffer(id, off + (256 * bs), 0x200);
 	if (vd == NULL)
 		return -1;
 
@@ -621,7 +1112,7 @@ anchor:
 	/* pick the primary descriptor from the list */
 	for (b = 0; b < count; b++) {
 		vd = (struct volume_descriptor *)
-		     get_buffer(id, (loc + b) * bs, 0x200);
+		     get_buffer(id, off + ((loc + b) * bs), 0x200);
 		if (vd == NULL)
 			return -1;
 
@@ -644,20 +1135,21 @@ pvd:
 
 	clen = vd->type.primary.ident.clen;
 	dbg("label string charsize=%i bit", clen);
-	if (clen == 8) 
+	if (clen == 8)
 		set_label_string(id, vd->type.primary.ident.c, 31);
 	else if (clen == 16)
 		set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
 
 found:
-	id->fs_type = UDF;
-	id->fs_name = "udf";
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_UDF;
+	id->type = "udf";
 
 	return 0;
 }
 
 #define ISO_SUPERBLOCK_OFFSET		0x8000
-static int probe_iso9660(struct volume_id *id)
+static int probe_iso9660(struct volume_id *id, __u64 off)
 {
 	union iso_super_block {
 		struct iso_header {
@@ -677,7 +1169,7 @@ static int probe_iso9660(struct volume_i
 	} __attribute__((__packed__)) *is;
 
 	is = (union iso_super_block *)
-	     get_buffer(id, ISO_SUPERBLOCK_OFFSET, 0x200);
+	     get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
 	if (is == NULL)
 		return -1;
 
@@ -691,40 +1183,557 @@ static int probe_iso9660(struct volume_i
 	return -1;
 
 found:
-	id->fs_type = ISO9660;
-	id->fs_name = "iso9660";
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_ISO9660;
+	id->type = "iso9660";
+
+	return 0;
+}
+
+#define UFS_MAGIC			0x00011954
+#define UFS2_MAGIC			0x19540119
+#define UFS_MAGIC_FEA			0x00195612
+#define UFS_MAGIC_LFN			0x00095014
+
+
+static int probe_ufs(struct volume_id *id, __u64 off)
+{
+	struct ufs_super_block {
+		__u32	fs_link;
+		__u32	fs_rlink;
+		__u32	fs_sblkno;
+		__u32	fs_cblkno;
+		__u32	fs_iblkno;
+		__u32	fs_dblkno;
+		__u32	fs_cgoffset;
+		__u32	fs_cgmask;
+		__u32	fs_time;
+		__u32	fs_size;
+		__u32	fs_dsize;
+		__u32	fs_ncg;	
+		__u32	fs_bsize;
+		__u32	fs_fsize;
+		__u32	fs_frag;
+		__u32	fs_minfree;
+		__u32	fs_rotdelay;
+		__u32	fs_rps;	
+		__u32	fs_bmask;
+		__u32	fs_fmask;
+		__u32	fs_bshift;
+		__u32	fs_fshift;
+		__u32	fs_maxcontig;
+		__u32	fs_maxbpg;
+		__u32	fs_fragshift;
+		__u32	fs_fsbtodb;
+		__u32	fs_sbsize;
+		__u32	fs_csmask;
+		__u32	fs_csshift;
+		__u32	fs_nindir;
+		__u32	fs_inopb;
+		__u32	fs_nspf;
+		__u32	fs_optim;
+		__u32	fs_npsect_state;
+		__u32	fs_interleave;
+		__u32	fs_trackskew;
+		__u32	fs_id[2];
+		__u32	fs_csaddr;
+		__u32	fs_cssize;
+		__u32	fs_cgsize;
+		__u32	fs_ntrak;
+		__u32	fs_nsect;
+		__u32	fs_spc;	
+		__u32	fs_ncyl;
+		__u32	fs_cpg;
+		__u32	fs_ipg;
+		__u32	fs_fpg;
+		struct ufs_csum {
+			__u32	cs_ndir;
+			__u32	cs_nbfree;
+			__u32	cs_nifree;
+			__u32	cs_nffree;
+		} __attribute__((__packed__)) fs_cstotal;
+		__s8	fs_fmod;
+		__s8	fs_clean;
+		__s8	fs_ronly;
+		__s8	fs_flags;
+		union {
+			struct {
+				__s8	fs_fsmnt[512];
+				__u32	fs_cgrotor;
+				__u32	fs_csp[31];
+				__u32	fs_maxcluster;
+				__u32	fs_cpc;
+				__u16	fs_opostbl[16][8];
+			} __attribute__((__packed__)) fs_u1;
+			struct {
+				__s8  fs_fsmnt[468];
+				__u8   fs_volname[32];
+				__u64  fs_swuid;
+				__s32  fs_pad;
+				__u32   fs_cgrotor;
+				__u32   fs_ocsp[28];
+				__u32   fs_contigdirs;
+				__u32   fs_csp;	
+				__u32   fs_maxcluster;
+				__u32   fs_active;
+				__s32   fs_old_cpc;
+				__s32   fs_maxbsize;
+				__s64   fs_sparecon64[17];
+				__s64   fs_sblockloc;
+				struct  ufs2_csum_total {
+					__u64	cs_ndir;
+					__u64	cs_nbfree;
+					__u64	cs_nifree;
+					__u64	cs_nffree;
+					__u64	cs_numclusters;
+					__u64	cs_spare[3];
+				} __attribute__((__packed__)) fs_cstotal;
+				struct  ufs_timeval {
+					__s32	tv_sec;
+					__s32	tv_usec;
+				} __attribute__((__packed__)) fs_time;
+				__s64    fs_size;
+				__s64    fs_dsize;
+				__u64    fs_csaddr;
+				__s64    fs_pendingblocks;
+				__s32    fs_pendinginodes;
+			} __attribute__((__packed__)) fs_u2;
+		}  fs_u11;
+		union {
+			struct {
+				__s32	fs_sparecon[53];
+				__s32	fs_reclaim;
+				__s32	fs_sparecon2[1];
+				__s32	fs_state;
+				__u32	fs_qbmask[2];
+				__u32	fs_qfmask[2];
+			} __attribute__((__packed__)) fs_sun;
+			struct {
+				__s32	fs_sparecon[53];
+				__s32	fs_reclaim;
+				__s32	fs_sparecon2[1];
+				__u32	fs_npsect;
+				__u32	fs_qbmask[2];
+				__u32	fs_qfmask[2];
+			} __attribute__((__packed__)) fs_sunx86;
+			struct {
+				__s32	fs_sparecon[50];
+				__s32	fs_contigsumsize;
+				__s32	fs_maxsymlinklen;
+				__s32	fs_inodefmt;
+				__u32	fs_maxfilesize[2];
+				__u32	fs_qbmask[2];
+				__u32	fs_qfmask[2];
+				__s32	fs_state;
+			} __attribute__((__packed__)) fs_44;
+		} fs_u2;
+		__s32	fs_postblformat;
+		__s32	fs_nrpos;
+		__s32	fs_postbloff;
+		__s32	fs_rotbloff;
+		__u32	fs_magic;
+		__u8	fs_space[1];
+	} __attribute__((__packed__)) *ufs;
+
+	__u32	magic;
+	int 	i;
+	int	offsets[] = {0, 8, 64, 256, -1};
+
+	for (i = 0; offsets[i] >= 0; i++) {	
+		ufs = (struct ufs_super_block *)
+			get_buffer(id, off + (offsets[i] * 0x400), 0x800);
+		if (ufs == NULL)
+			return -1;
+
+		dbg("offset 0x%x", offsets[i] * 0x400);
+		magic = be32_to_cpu(ufs->fs_magic);
+		if ((magic == UFS_MAGIC) ||
+		    (magic == UFS2_MAGIC) ||
+		    (magic == UFS_MAGIC_FEA) ||
+		    (magic == UFS_MAGIC_LFN)) {
+			dbg("magic 0x%08x(be)", magic);
+			goto found;
+		}
+		magic = le32_to_cpu(ufs->fs_magic);
+		if ((magic == UFS_MAGIC) ||
+		    (magic == UFS2_MAGIC) ||
+		    (magic == UFS_MAGIC_FEA) ||
+		    (magic == UFS_MAGIC_LFN)) {
+			dbg("magic 0x%08x(le)", magic);
+			goto found;
+		}
+	}
+	return -1;
+
+found:
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_UFS;
+	id->type = "ufs";
+
+	return 0;
+}
+
+static int probe_mac_partition_map(struct volume_id *id, __u64 off)
+{
+	struct mac_driver_desc {
+		__u8	signature[2];
+		__u16	block_size;
+		__u32	block_count;
+	} __attribute__((__packed__)) *driver;
+
+	struct mac_partition {
+		__u8	signature[2];
+		__u16	res1;
+		__u32	map_count;
+		__u32	start_block;
+		__u32	block_count;
+		__u8	name[32];
+		__u8	type[32];
+	} __attribute__((__packed__)) *part;
+
+	const __u8 *buf;
+
+	buf = get_buffer(id, off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	part = (struct mac_partition *) buf;
+	if ((strncmp(part->signature, "PM", 2) == 0) &&
+	    (strncmp(part->type, "Apple_partition_map", 19) == 0)) {
+		/* linux creates an own subdevice for the map
+		 * just return the type if the drive header is missing */
+		id->usage_id = VOLUME_ID_PARTITIONTABLE;
+		id->type_id = VOLUME_ID_MACPARTMAP;
+		id->type = "mac_partition_map";
+		return 0;
+	}
+
+	driver = (struct mac_driver_desc *) buf;
+	if (strncmp(driver->signature, "ER", 2) == 0) {
+		/* we are on a main device, like a CD
+		 * just try to probe the first partition from the map */
+		unsigned int bsize = be16_to_cpu(driver->block_size);
+		int part_count;
+		int i;
+
+		/* get first entry of partition table */
+		buf = get_buffer(id, off +  bsize, 0x200);
+		if (buf == NULL)
+			return -1;
+
+		part = (struct mac_partition *) buf;
+		if (strncmp(part->signature, "PM", 2) != 0)
+			return -1;
+
+		part_count = be32_to_cpu(part->map_count);
+		dbg("expecting %d partition entries", part_count);
+
+		if (id->partitions != NULL)
+			free(id->partitions);
+		id->partitions =
+			malloc(part_count * sizeof(struct volume_id_partition));
+		if (id->partitions == NULL)
+			return -1;
+		memset(id->partitions, 0x00, sizeof(struct volume_id_partition));
+
+		id->partition_count = part_count;
+
+		for (i = 0; i < part_count; i++) {
+			__u64 poff;
+			__u64 plen;
+
+			buf = get_buffer(id, off + ((i+1) * bsize), 0x200);
+			if (buf == NULL)
+				return -1;
+
+			part = (struct mac_partition *) buf;
+			if (strncmp(part->signature, "PM", 2) != 0)
+				return -1;
+
+			poff = be32_to_cpu(part->start_block) * bsize;
+			plen = be32_to_cpu(part->block_count) * bsize;
+			dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
+			    part->type, poff, plen);
+
+			id->partitions[i].off = poff;
+			id->partitions[i].len = plen;
+
+			if (strncmp(part->type, "Apple_Free", 10) == 0) {
+				id->partitions[i].usage_id = VOLUME_ID_UNUSED;
+			} else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
+				id->partitions[i].usage_id = VOLUME_ID_PARTITIONTABLE;
+				id->partitions[i].type_id = VOLUME_ID_MACPARTMAP;
+			} else {
+				id->partitions[i].usage_id = VOLUME_ID_UNPROBED;
+			}
+		}
+		id->usage_id = VOLUME_ID_PARTITIONTABLE;
+		id->type_id = VOLUME_ID_MACPARTMAP;
+		id->type = "mac_partition_map";
+		return 0;
+	}
+
+	return -1;
+}
+
+#define HFS_SUPERBLOCK_OFFSET		0x400
+#define HFS_NODE_LEAF			0xff
+#define HFSPLUS_POR_CNID		1
+static int probe_hfs_hfsplus(struct volume_id *id, __u64 off)
+{
+	struct finder_info {
+		__u32	boot_folder;
+		__u32	start_app;
+		__u32	open_folder;
+		__u32	os9_folder;
+		__u32	reserved;
+		__u32	osx_folder;
+		__u8	id[8];
+	} __attribute__((__packed__));
+
+	struct hfs_mdb {
+		__u8	signature[2];
+		__u32	cr_date;
+		__u32	ls_Mod;
+		__u16	atrb;
+		__u16	nm_fls;
+		__u16	vbm_st;
+		__u16	alloc_ptr;
+		__u16	nm_al_blks;
+		__u32	al_blk_size;
+		__u32	clp_size;
+		__u16	al_bl_st;
+		__u32	nxt_cnid;
+		__u16	free_bks;
+		__u8	label_len;
+		__u8	label[27];
+		__u32	vol_bkup;
+		__u16	vol_seq_num;
+		__u32	wr_cnt;
+		__u32	xt_clump_size;
+		__u32	ct_clump_size;
+		__u16	num_root_dirs;
+		__u32	file_count;
+		__u32	dir_count;
+		struct finder_info finfo;
+		__u8	embed_sig[2];
+		__u16	embed_startblock;
+		__u16	embed_blockcount;
+	} __attribute__((__packed__)) *hfs;
+
+	struct hfsplus_bnode_descriptor {
+		__u32	next;
+		__u32	prev;
+		__u8	type;
+		__u8	height;
+		__u16	num_recs;
+		__u16	reserved;
+	} __attribute__((__packed__));
+
+	struct hfsplus_bheader_record {
+		__u16	depth;
+		__u32	root;
+		__u32	leaf_count;
+		__u32	leaf_head;
+		__u32	leaf_tail;
+		__u16	node_size;
+	} __attribute__((__packed__));
+
+	struct hfsplus_catalog_key {
+		__u16	key_len;
+		__u32	parent_id;
+		__u16	unicode_len;
+		__u8	unicode[255 * 2];
+	} __attribute__((__packed__));
+
+	struct hfsplus_extent {
+		__u32 start_block;
+		__u32 block_count;
+	} __attribute__((__packed__));
+
+	struct hfsplus_fork {
+		__u64 total_size;
+        	__u32 clump_size;
+		__u32 total_blocks;
+		struct hfsplus_extent extents[8];
+	} __attribute__((__packed__));
+
+	struct hfsplus_vol_header {
+		__u8	signature[2];
+		__u16	version;
+		__u32	attributes;
+		__u32	last_mount_vers;
+		__u32	reserved;
+		__u32	create_date;
+		__u32	modify_date;
+		__u32	backup_date;
+		__u32	checked_date;
+		__u32	file_count;
+		__u32	folder_count;
+		__u32	blocksize;
+		__u32	total_blocks;
+		__u32	free_blocks;
+		__u32	next_alloc;
+		__u32	rsrc_clump_sz;
+		__u32	data_clump_sz;
+		__u32	next_cnid;
+		__u32	write_count;
+		__u64	encodings_bmp;
+		struct finder_info finfo;
+		struct hfsplus_fork alloc_file;
+		struct hfsplus_fork ext_file;
+		struct hfsplus_fork cat_file;
+		struct hfsplus_fork attr_file;
+		struct hfsplus_fork start_file;
+	} __attribute__((__packed__)) *hfsplus;
+
+	unsigned int blocksize;
+	unsigned int cat_block;
+	unsigned int cat_block_count;
+	unsigned int cat_off;
+	unsigned int cat_len;
+	unsigned int leaf_node_head;
+	unsigned int leaf_node_size;
+	unsigned int alloc_block_size;
+	unsigned int alloc_first_block;
+	unsigned int embed_first_block;
+	struct hfsplus_bnode_descriptor *descr;
+	struct hfsplus_bheader_record *bnode;
+	struct hfsplus_catalog_key *key;
+	unsigned int	label_len;
+	const __u8 *buf;
+
+	buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+	if (buf == NULL)
+                return -1;
+
+	hfs = (struct hfs_mdb *) buf;
+	if (strncmp(hfs->signature, "BD", 2) != 0)
+		goto checkplus;
+
+	/* it may be just a hfs wrapper for hfs+ */
+	if (strncmp(hfs->embed_sig, "H+", 2) == 0) {
+		alloc_block_size = be32_to_cpu(hfs->al_blk_size);
+		dbg("alloc_block_size 0x%x", alloc_block_size);
+
+		alloc_first_block = be16_to_cpu(hfs->al_bl_st);
+		dbg("alloc_first_block 0x%x", alloc_first_block);
+
+		embed_first_block = be16_to_cpu(hfs->embed_startblock);
+		dbg("embed_first_block 0x%x", embed_first_block);
+
+		off += (alloc_first_block * 512) +
+		       (embed_first_block * alloc_block_size);
+		dbg("hfs wrapped hfs+ found at offset 0x%llx", off);
+
+		buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+		if (buf == NULL)
+			return -1;
+		goto checkplus;
+	}
+
+	if (hfs->label_len > 0 && hfs->label_len < 28) {
+		set_label_raw(id, hfs->label, hfs->label_len);
+		set_label_string(id, hfs->label, hfs->label_len) ;
+	}
+
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_HFS;
+	id->type = "hfs";
+
+	return 0;
+
+checkplus:
+	hfsplus = (struct hfsplus_vol_header *) buf;
+	if (strncmp(hfsplus->signature, "H+", 2) == 0)
+		goto hfsplus;
+	if (strncmp(hfsplus->signature, "HX", 2) == 0)
+		goto hfsplus;
+	return -1;
+
+hfsplus:
+	blocksize = be32_to_cpu(hfsplus->blocksize);
+	cat_block = be32_to_cpu(hfsplus->cat_file.extents[0].start_block);
+	cat_block_count = be32_to_cpu(hfsplus->cat_file.extents[0].block_count);
+	cat_off = (cat_block * blocksize);
+	cat_len = cat_block_count * blocksize;
+	dbg("catalog start 0x%llx, len 0x%x", off + cat_off, cat_len);
+
+	buf = get_buffer(id, off + cat_off, 0x2000);
+	if (buf == NULL)
+		goto found;
+
+	bnode = (struct hfsplus_bheader_record *)
+		&buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+	leaf_node_head = be32_to_cpu(bnode->leaf_head);
+	leaf_node_size = be16_to_cpu(bnode->node_size);
+
+	dbg("catalog leaf node 0x%x, size 0x%x",
+	    leaf_node_head, leaf_node_size);
+
+	buf = get_buffer(id, off + cat_off + (leaf_node_head * leaf_node_size),
+			 leaf_node_size);
+	if (buf == NULL)
+		goto found;
+
+	descr = (struct hfsplus_bnode_descriptor *) buf;
+	dbg("descriptor type 0x%x", descr->type);
+	if (descr->type != HFS_NODE_LEAF)
+		goto found;
+
+	key = (struct hfsplus_catalog_key *)
+		&buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+	dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
+	if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
+		goto found;
+
+	label_len = be16_to_cpu(key->unicode_len) * 2;
+	dbg("label unicode16 len %i", label_len);
+	set_label_raw(id, key->unicode, label_len);
+	set_label_unicode16(id, key->unicode, BE, label_len);
+
+found:
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_HFSPLUS;
+	id->type = "hfsplus";
 
 	return 0;
 }
 
 #define MFT_RECORD_VOLUME			3
-#define MFT_RECORD_ATTR_VOLUME_NAME		0x60u
-#define MFT_RECORD_ATTR_OBJECT_ID		0x40u
+#define MFT_RECORD_ATTR_VOLUME_NAME		0x60
+#define MFT_RECORD_ATTR_VOLUME_INFO		0x70
+#define MFT_RECORD_ATTR_OBJECT_ID		0x40
 #define MFT_RECORD_ATTR_END			0xffffffffu
-static int probe_ntfs(struct volume_id *id)
+static int probe_ntfs(struct volume_id *id, __u64 off)
 {
 	struct ntfs_super_block {
 		__u8	jump[3];
 		__u8	oem_id[8];
-		struct bios_param_block {
-			__u16	bytes_per_sector;
-			__u8	sectors_per_cluster;
-			__u16	reserved_sectors;
-			__u8	fats;
-			__u16	root_entries;
-			__u16	sectors;
-			__u8	media_type;		/* 0xf8 = hard disk */
-			__u16	sectors_per_fat;
-			__u16	sectors_per_track;
-			__u16	heads;
-			__u32	hidden_sectors;
-			__u32	large_sectors;
-		} __attribute__((__packed__)) bpb;
-		__u8 unused[4];
+		__u16	bytes_per_sector;
+		__u8	sectors_per_cluster;
+		__u16	reserved_sectors;
+		__u8	fats;
+		__u16	root_entries;
+		__u16	sectors;
+		__u8	media_type;
+		__u16	sectors_per_fat;
+		__u16	sectors_per_track;
+		__u16	heads;
+		__u32	hidden_sectors;
+		__u32	large_sectors;
+		__u16	unused[2];
 		__u64	number_of_sectors;
 		__u64	mft_cluster_location;
 		__u64	mft_mirror_cluster_location;
 		__s8	cluster_per_mft_record;
+		__u8	reserved1[3];
+		__s8	cluster_per_index_record;
+		__u8	reserved2[3];
+		__u8	volume_serial[8];
+		__u16	checksum;
 	} __attribute__((__packed__)) *ns;
 
 	struct master_file_table_record {
@@ -752,28 +1761,36 @@ static int probe_ntfs(struct volume_id *
 		__u16	value_offset;
 	} __attribute__((__packed__)) *attr;
 
-	unsigned int	sector_size;
-	unsigned int	cluster_size;
-	unsigned long	mft_cluster;
-	unsigned long	mft_off;
-	unsigned int	mft_record_size;
-	unsigned int	attr_type;
-	unsigned int	attr_off;
-	unsigned int	attr_len;
-	unsigned int	val_off;
-	unsigned int	val_len;
+	struct volume_info {
+		__u64 reserved;
+		__u8 major_ver;
+		__u8 minor_ver;
+	} __attribute__((__packed__)) *info;
+
+	unsigned int sector_size;
+	unsigned int cluster_size;
+	__u64 mft_cluster;
+	__u64 mft_off;
+	unsigned int mft_record_size;
+	unsigned int attr_type;
+	unsigned int attr_off;
+	unsigned int attr_len;
+	unsigned int val_off;
+	unsigned int val_len;
 	const __u8 *buf;
 	const __u8 *val;
 
-	ns = (struct ntfs_super_block *) get_buffer(id, 0, 0x200);
+	ns = (struct ntfs_super_block *) get_buffer(id, off, 0x200);
 	if (ns == NULL)
 		return -1;
 
 	if (strncmp(ns->oem_id, "NTFS", 4) != 0)
 		return -1;
 
-	sector_size = le16_to_cpu(ns->bpb.bytes_per_sector);
-	cluster_size = ns->bpb.sectors_per_cluster * sector_size;
+	set_uuid(id, ns->volume_serial, 8);
+
+	sector_size = le16_to_cpu(ns->bytes_per_sector);
+	cluster_size = ns->sectors_per_cluster * sector_size;
 	mft_cluster = le64_to_cpu(ns->mft_cluster_location);
 	mft_off = mft_cluster * cluster_size;
 
@@ -785,22 +1802,19 @@ static int probe_ntfs(struct volume_id *
 
 	dbg("sectorsize  0x%x", sector_size);
 	dbg("clustersize 0x%x", cluster_size);
-	dbg("mftcluster  %li", mft_cluster);
-	dbg("mftoffset  0x%lx", mft_off);
+	dbg("mftcluster  %lli", mft_cluster);
+	dbg("mftoffset  0x%llx", mft_off);
 	dbg("cluster per mft_record  %i", ns->cluster_per_mft_record);
 	dbg("mft record size  %i", mft_record_size);
 
-	buf = get_buffer(id, mft_off + (MFT_RECORD_VOLUME * mft_record_size),
+	buf = get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
 			 mft_record_size);
 	if (buf == NULL)
 		goto found;
 
 	mftr = (struct master_file_table_record*) buf;
 
-	dbg("mftr->magic[0] = '%c' %03d, 0x%02x", mftr->magic[0], mftr->magic[0], mftr->magic[0]);
-	dbg("mftr->magic[1] = '%c' %03d, 0x%02x", mftr->magic[1], mftr->magic[1], mftr->magic[1]);
-	dbg("mftr->magic[2] = '%c' %03d, 0x%02x", mftr->magic[2], mftr->magic[2], mftr->magic[2]);
-	dbg("mftr->magic[3] = '%c' %03d, 0x%02x", mftr->magic[3], mftr->magic[3], mftr->magic[3]);
+	dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
 	if (strncmp(mftr->magic, "FILE", 4) != 0)
 		goto found;
 
@@ -813,6 +1827,13 @@ static int probe_ntfs(struct volume_id *
 		attr_len = le16_to_cpu(attr->len);
 		val_off = le16_to_cpu(attr->value_offset);
 		val_len = le32_to_cpu(attr->value_len);
+		attr_off += attr_len;
+
+		if (attr_len == 0)
+			break;
+
+		if (attr_off >= mft_record_size)
+			break;
 
 		if (attr_type == MFT_RECORD_ATTR_END)
 			break;
@@ -820,136 +1841,182 @@ static int probe_ntfs(struct volume_id *
 		dbg("found attribute type 0x%x, len %i, at offset %i",
 		    attr_type, attr_len, attr_off);
 
+		if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
+			dbg("found info, len %i", val_len);
+			info = (struct volume_info*) (((__u8 *) attr) + val_off);
+			snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1,
+				 "%u.%u", info->major_ver, info->minor_ver);
+		}
+
 		if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
 			dbg("found label, len %i", val_len);
 			if (val_len > VOLUME_ID_LABEL_SIZE)
 				val_len = VOLUME_ID_LABEL_SIZE;
 
-			val = &((__u8 *) attr)[val_off];
+			val = ((__u8 *) attr) + val_off;
 			set_label_raw(id, val, val_len);
 			set_label_unicode16(id, val, LE, val_len);
 		}
-
-		if (attr_type == MFT_RECORD_ATTR_OBJECT_ID) {
-			dbg("found uuid");
-			val = &((__u8 *) attr)[val_off];
-			set_uuid(id, val, 16);
-		}
-
-		if (attr_len == 0)
-			break;
-		attr_off += attr_len;
-		if (attr_off >= mft_record_size)
-			break;
 	}
 
 found:
-	id->fs_type = NTFS;
-	id->fs_name = "ntfs";
+	id->usage_id = VOLUME_ID_FILESYSTEM;
+	id->type_id = VOLUME_ID_NTFS;
+	id->type = "ntfs";
 
 	return 0;
 }
 
 #define LARGEST_PAGESIZE			0x4000
-static int probe_swap(struct volume_id *id)
+static int probe_swap(struct volume_id *id, __u64 off)
 {
 	const __u8 *sig;
 	unsigned int page;
 
 	/* huhh, the swap signature is on the end of the PAGE_SIZE */
 	for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
-			sig = get_buffer(id, page-10, 10);
+			sig = get_buffer(id, off + page-10, 10);
 			if (sig == NULL)
 				return -1;
 
-			if (strncmp(sig, "SWAP-SPACE", 10) == 0)
+			if (strncmp(sig, "SWAP-SPACE", 10) == 0) {
+				strcpy(id->type_version, "1");
 				goto found;
-			if (strncmp(sig, "SWAPSPACE2", 10) == 0)
+			}
+			if (strncmp(sig, "SWAPSPACE2", 10) == 0) {
+				strcpy(id->type_version, "2");
 				goto found;
+			}
 	}
 	return -1;
 
 found:
-	id->fs_type = SWAP;
-	id->fs_name = "swap";
+	id->usage_id = VOLUME_ID_OTHER;
+	id->type_id = VOLUME_ID_SWAP;
+	id->type = "swap";
 
 	return 0;
 }
 
 /* probe volume for filesystem type and try to read label+uuid */
-int volume_id_probe(struct volume_id *id, enum filesystem_type fs_type)
+int volume_id_probe(struct volume_id *id,
+		    enum volume_id_type type,
+		    unsigned long long off,
+		    unsigned long long size)
 {
 	int rc;
 
 	if (id == NULL)
 		return -EINVAL;
 
-	switch (fs_type) {
-	case EXT3:
-	case EXT2:
-		rc = probe_ext(id);
+	switch (type) {
+	case VOLUME_ID_MSDOSPARTTABLE:
+		rc = probe_msdos_part_table(id, off);
+		break;
+	case VOLUME_ID_EXT3:
+	case VOLUME_ID_EXT2:
+		rc = probe_ext(id, off);
+		break;
+	case VOLUME_ID_REISERFS:
+		rc = probe_reiserfs(id, off);
+		break;
+	case VOLUME_ID_XFS:
+		rc = probe_xfs(id, off);
+		break;
+	case VOLUME_ID_JFS:
+		rc = probe_jfs(id, off);
+		break;
+	case VOLUME_ID_VFAT:
+		rc = probe_vfat(id, off);
+		break;
+	case VOLUME_ID_UDF:
+		rc = probe_udf(id, off);
 		break;
-	case REISER:
-		rc = probe_reiser(id);
+	case VOLUME_ID_ISO9660:
+		rc = probe_iso9660(id, off);
 		break;
-	case XFS:
-		rc = probe_xfs(id);
+	case VOLUME_ID_MACPARTMAP:
+		rc = probe_mac_partition_map(id, off);
 		break;
-	case JFS:
-		rc = probe_jfs(id);
+	case VOLUME_ID_HFS:
+	case VOLUME_ID_HFSPLUS:
+		rc = probe_hfs_hfsplus(id, off);
 		break;
-	case MSDOS:
-		rc = probe_msdos(id);
+	case VOLUME_ID_UFS:
+		rc = probe_ufs(id, off);
 		break;
-	case VFAT:
-		rc = probe_vfat(id);
+	case VOLUME_ID_NTFS:
+		rc = probe_ntfs(id, off);
 		break;
-	case UDF:
-		rc = probe_udf(id);
+	case VOLUME_ID_SWAP:
+		rc = probe_swap(id, off);
 		break;
-	case ISO9660:
-		rc = probe_iso9660(id);
+	case VOLUME_ID_LINUX_RAID:
+		rc = probe_linux_raid(id, off, size);
 		break;
-	case NTFS:
-		rc = probe_ntfs(id);
+	case VOLUME_ID_LVM1:
+		rc = probe_lvm1(id, off);
 		break;
-	case SWAP:
-		rc = probe_swap(id);
+	case VOLUME_ID_LVM2:
+		rc = probe_lvm2(id, off);
 		break;
-	case ALL:
+	case VOLUME_ID_ALL:
 	default:
+		rc = probe_linux_raid(id, off, size);
+		if (rc == 0)
+			break;
+
+		/* signature in the first block */
+		rc = probe_ntfs(id, off);
+		if (rc == 0)
+			break;
+		rc = probe_vfat(id, off);
+		if (rc == 0)
+			break;
+		rc = probe_msdos_part_table(id, off);
+		if (rc == 0)
+			break;
+		rc = probe_mac_partition_map(id, off);
+		if (rc == 0)
+			break;
+		rc = probe_xfs(id, off);
+		if (rc == 0)
+			break;
+
 		/* fill buffer with maximum */
 		get_buffer(id, 0, SB_BUFFER_SIZE);
-		rc = probe_ext(id);
+
+		rc = probe_swap(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_reiser(id);
+		rc = probe_ext(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_xfs(id);
+		rc = probe_reiserfs(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_jfs(id);
+		rc = probe_jfs(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_msdos(id);
+		rc = probe_udf(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_vfat(id);
+		rc = probe_iso9660(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_udf(id);
+		rc = probe_hfs_hfsplus(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_iso9660(id);
+		rc = probe_ufs(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_ntfs(id);
+		rc = probe_lvm1(id, off);
 		if (rc == 0)
 			break;
-		rc = probe_swap(id);
+		rc = probe_lvm2(id, off);
 		if (rc == 0)
 			break;
+
 		rc = -1;
 	}
 
@@ -982,9 +2049,11 @@ struct volume_id *volume_id_open_node(co
 	struct volume_id *id;
 	int fd;
 
-	fd = open(path, O_RDONLY);
-	if (fd < 0)
+	fd = open(path, O_RDONLY | O_NONBLOCK);
+	if (fd < 0) {
+		dbg("unable to open '%s'", path);
 		return NULL;
+	}
 
 	id = volume_id_open_fd(fd);
 	if (id == NULL)
@@ -1028,6 +2097,9 @@ void volume_id_close(struct volume_id *i
 		close(id->fd);
 
 	free_buffer(id);
+
+	if (id->partitions != NULL)
+		free(id->partitions);
 
 	free(id);
 }
===== extras/volume_id/volume_id.h 1.3 vs edited =====
--- 1.3/extras/volume_id/volume_id.h	2004-06-24 02:25:42 +02:00
+++ edited/extras/volume_id/volume_id.h	2004-08-30 01:40:36 +02:00
@@ -21,42 +21,72 @@
 #ifndef _VOLUME_ID_H_
 #define _VOLUME_ID_H_
 
-#define VOLUME_ID_VERSION		004
+#define VOLUME_ID_VERSION		022
 
 #define VOLUME_ID_LABEL_SIZE		64
 #define VOLUME_ID_UUID_SIZE		16
 #define VOLUME_ID_UUID_STRING_SIZE	37
-#define VOLUME_ID_PATH_MAX		255
+#define VOLUME_ID_FORMAT_SIZE		32
+#define VOLUME_ID_PATH_MAX		256
+#define VOLUME_ID_PARTITIONS_MAX	16
+
+enum volume_id_usage {
+	VOLUME_ID_UNUSED,
+	VOLUME_ID_UNPROBED,
+	VOLUME_ID_OTHER,
+	VOLUME_ID_FILESYSTEM,
+	VOLUME_ID_PARTITIONTABLE,
+	VOLUME_ID_RAID
+};
 
+enum volume_id_type {
+	VOLUME_ID_ALL,
+	VOLUME_ID_MSDOSPARTTABLE,
+	VOLUME_ID_MSDOSEXTENDED,
+	VOLUME_ID_SWAP,
+	VOLUME_ID_EXT2,
+	VOLUME_ID_EXT3,
+	VOLUME_ID_REISERFS,
+	VOLUME_ID_XFS,
+	VOLUME_ID_JFS,
+	VOLUME_ID_VFAT,
+	VOLUME_ID_UDF,
+	VOLUME_ID_ISO9660,
+	VOLUME_ID_NTFS,
+	VOLUME_ID_MACPARTMAP,
+	VOLUME_ID_HFS,
+	VOLUME_ID_HFSPLUS,
+	VOLUME_ID_UFS,
+	VOLUME_ID_LINUX_RAID,
+	VOLUME_ID_LVM1,
+	VOLUME_ID_LVM2
+};
 
-enum filesystem_type {
-	ALL,
-	EXT2,
-	EXT3,
-	REISER,
-	XFS,
-	JFS,
-	MSDOS,
-	VFAT,
-	UDF,
-	ISO9660,
-	NTFS,
-	SWAP
+struct volume_id_partition {
+	enum		volume_id_usage usage_id;
+	enum		volume_id_type type_id;
+	char		*type;
+	unsigned long long off;
+	unsigned long long len;
 };
 
 struct volume_id {
 	unsigned char	label_raw[VOLUME_ID_LABEL_SIZE];
 	unsigned int	label_raw_len;
-	char		label_string[VOLUME_ID_LABEL_SIZE+1];
-	unsigned char	uuid[VOLUME_ID_UUID_SIZE];
-	char		uuid_string[VOLUME_ID_UUID_STRING_SIZE];
-	enum		filesystem_type fs_type;
-	char		*fs_name;
+	char		label[VOLUME_ID_LABEL_SIZE+1];
+	unsigned char	uuid_raw[VOLUME_ID_UUID_SIZE];
+	char		uuid[VOLUME_ID_UUID_STRING_SIZE];
+	enum		volume_id_usage usage_id;
+	enum		volume_id_type type_id;
+	char		*type;
+	char		type_version[VOLUME_ID_FORMAT_SIZE];
+	struct volume_id_partition *partitions;
+	unsigned int	partition_count;
 	int		fd;
 	unsigned char	*sbbuf;
 	unsigned int	sbbuf_len;
 	unsigned char	*seekbuf;
-	unsigned int	seekbuf_off;
+	unsigned long long seekbuf_off;
 	unsigned int	seekbuf_len;
 	int		fd_close;
 };
@@ -71,7 +101,8 @@ extern struct volume_id *volume_id_open_
 extern struct volume_id *volume_id_open_dev_t(dev_t devt);
 
 /* probe volume for filesystem type and try to read label/uuid */
-extern int volume_id_probe(struct volume_id *id, enum filesystem_type fs_type);
+extern int volume_id_probe(struct volume_id *id, enum volume_id_type type,
+			   unsigned long long off, unsigned long long size);
 
 /* free allocated device info */
 extern void volume_id_close(struct volume_id *id);

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [patch] update udev_volume_id
@ 2004-09-05  8:07 Greg KH
  0 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2004-09-05  8:07 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Aug 30, 2004 at 02:18:15AM +0200, Kay Sievers wrote:
> Here is an update for the volume_id callout to catch up to the latest
> and greatest:

Nice, applied, thanks.

greg k-h


-------------------------------------------------------
This SF.Net email is sponsored by BEA Weblogic Workshop
FREE Java Enterprise J2EE developer tools!
Get your free copy of BEA WebLogic Workshop 8.1 today.
http://ads.osdn.com/?ad_idP47&alloc_id\x10808&op=click
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2004-09-05  8:07 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-09-05  8:07 [patch] update udev_volume_id Greg KH
  -- strict thread matches above, loose matches on Subject: below --
2004-08-30  0:18 Kay Sievers
2004-06-24  0:44 [PATCH] " Kay Sievers
2004-06-26  0:29 ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).