2 * volume_id - reads filesystem label and uuid
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6 * The superblock structs are taken from the linux kernel sources
7 * and the libblkid living inside the e2fsprogs. This is a simple
8 * straightforward implementation for reading the label strings of the
9 * most common filesystems.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42 #include <asm/types.h>
44 #include "volume_id.h"
45 #include "volume_id_logging.h"
47 #define bswap16(x) (__u16)((((__u16)(x) & 0x00ffu) << 8) | \
48 (((__u16)(x) & 0xff00u) >> 8))
50 #define bswap32(x) (__u32)((((__u32)(x) & 0xff000000u) >> 24) | \
51 (((__u32)(x) & 0x00ff0000u) >> 8) | \
52 (((__u32)(x) & 0x0000ff00u) << 8) | \
53 (((__u32)(x) & 0x000000ffu) << 24))
55 #define bswap64(x) (__u64)((((__u64)(x) & 0xff00000000000000ull) >> 56) | \
56 (((__u64)(x) & 0x00ff000000000000ull) >> 40) | \
57 (((__u64)(x) & 0x0000ff0000000000ull) >> 24) | \
58 (((__u64)(x) & 0x000000ff00000000ull) >> 8) | \
59 (((__u64)(x) & 0x00000000ff000000ull) << 8) | \
60 (((__u64)(x) & 0x0000000000ff0000ull) << 24) | \
61 (((__u64)(x) & 0x000000000000ff00ull) << 40) | \
62 (((__u64)(x) & 0x00000000000000ffull) << 56))
64 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
65 #define le16_to_cpu(x) (x)
66 #define le32_to_cpu(x) (x)
67 #define le64_to_cpu(x) (x)
68 #define be16_to_cpu(x) bswap16(x)
69 #define be32_to_cpu(x) bswap32(x)
70 #elif (__BYTE_ORDER == __BIG_ENDIAN)
71 #define le16_to_cpu(x) bswap16(x)
72 #define le32_to_cpu(x) bswap32(x)
73 #define le64_to_cpu(x) bswap64(x)
74 #define be16_to_cpu(x) (x)
75 #define be32_to_cpu(x) (x)
78 /* size of superblock buffer, reiserfs block is at 64k */
79 #define SB_BUFFER_SIZE 0x11000
80 /* size of seek buffer 4k */
81 #define SEEK_BUFFER_SIZE 0x10000
84 static void set_label_raw(struct volume_id *id,
85 const __u8 *buf, unsigned int count)
87 memcpy(id->label_raw, buf, count);
88 id->label_raw_len = count;
91 static void set_label_string(struct volume_id *id,
92 const __u8 *buf, unsigned int count)
96 memcpy(id->label, buf, count);
98 /* remove trailing whitespace */
99 i = strnlen(id->label, count);
101 if (! isspace(id->label[i]))
104 id->label[i+1] = '\0';
109 static void set_label_unicode16(struct volume_id *id,
111 unsigned int endianess,
118 for (i = 0; i + 2 <= count; i += 2) {
120 c = (buf[i+1] << 8) | buf[i];
122 c = (buf[i] << 8) | buf[i+1];
126 } else if (c < 0x80) {
127 id->label[j++] = (__u8) c;
128 } else if (c < 0x800) {
129 id->label[j++] = (__u8) (0xc0 | (c >> 6));
130 id->label[j++] = (__u8) (0x80 | (c & 0x3f));
132 id->label[j++] = (__u8) (0xe0 | (c >> 12));
133 id->label[j++] = (__u8) (0x80 | ((c >> 6) & 0x3f));
134 id->label[j++] = (__u8) (0x80 | (c & 0x3f));
146 static void set_uuid(struct volume_id *id, const __u8 *buf, enum uuid_format format)
149 unsigned int count = 0;
162 memcpy(id->uuid_raw, buf, count);
164 /* if set, create string in the same format, the native platform uses */
165 for (i = 0; i < count; i++)
173 sprintf(id->uuid, "%02X%02X-%02X%02X",
174 buf[3], buf[2], buf[1], buf[0]);
177 sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X",
178 buf[7], buf[6], buf[5], buf[4],
179 buf[3], buf[2], buf[1], buf[0]);
182 sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X",
183 buf[0], buf[1], buf[2], buf[3],
184 buf[4], buf[5], buf[6], buf[7]);
188 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
189 buf[0], buf[1], buf[2], buf[3],
193 buf[10], buf[11], buf[12], buf[13], buf[14],buf[15]);
198 static __u8 *get_buffer(struct volume_id *id, __u64 off, unsigned int len)
200 unsigned int buf_len;
202 dbg("get buffer off 0x%llx, len 0x%x", off, len);
203 /* check if requested area fits in superblock buffer */
204 if (off + len <= SB_BUFFER_SIZE) {
205 if (id->sbbuf == NULL) {
206 id->sbbuf = malloc(SB_BUFFER_SIZE);
207 if (id->sbbuf == NULL)
211 /* check if we need to read */
212 if ((off + len) > id->sbbuf_len) {
213 dbg("read sbbuf len:0x%llx", off + len);
214 lseek(id->fd, 0, SEEK_SET);
215 buf_len = read(id->fd, id->sbbuf, off + len);
216 dbg("got 0x%x (%i) bytes", buf_len, buf_len);
217 id->sbbuf_len = buf_len;
218 if (buf_len < off + len)
222 return &(id->sbbuf[off]);
224 if (len > SEEK_BUFFER_SIZE) {
225 dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
229 /* get seek buffer */
230 if (id->seekbuf == NULL) {
231 id->seekbuf = malloc(SEEK_BUFFER_SIZE);
232 if (id->seekbuf == NULL)
236 /* check if we need to read */
237 if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
238 dbg("read seekbuf off:0x%llx len:0x%x", off, len);
239 if (lseek(id->fd, off, SEEK_SET) == -1)
241 buf_len = read(id->fd, id->seekbuf, len);
242 dbg("got 0x%x (%i) bytes", buf_len, buf_len);
243 id->seekbuf_off = off;
244 id->seekbuf_len = buf_len;
246 dbg("requested 0x%x bytes, got only 0x%x bytes", len, buf_len);
251 return &(id->seekbuf[off - id->seekbuf_off]);
255 static void free_buffer(struct volume_id *id)
257 if (id->sbbuf != NULL) {
262 if (id->seekbuf != NULL) {
269 #define HPT37X_CONFIG_OFF 0x1200
270 #define HPT37X_MAGIC_OK 0x5a7816f0
271 #define HPT37X_MAGIC_BAD 0x5a7816fd
272 static int probe_highpoint_ataraid(struct volume_id *id, __u64 off)
279 } __attribute__((packed)) *hpt;
283 buf = get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200);
287 hpt = (struct hpt37x *) buf;
289 if (hpt->magic != HPT37X_MAGIC_OK && hpt->magic != HPT37X_MAGIC_BAD)
292 id->usage_id = VOLUME_ID_RAID;
293 id->type_id = VOLUME_ID_HPTRAID;
294 id->type = "hpt_ataraid_member";
299 #define LVM1_SB_OFF 0x400
300 #define LVM1_MAGIC "HM"
301 static int probe_lvm1(struct volume_id *id, __u64 off)
303 struct lvm2_super_block {
305 } __attribute__((packed)) *lvm;
309 buf = get_buffer(id, off + LVM1_SB_OFF, 0x800);
313 lvm = (struct lvm2_super_block *) buf;
315 if (strncmp(lvm->id, LVM1_MAGIC, 2) != 0)
318 id->usage_id = VOLUME_ID_RAID;
319 id->type_id = VOLUME_ID_LVM1;
320 id->type = "LVM1_member";
325 #define LVM2_LABEL_ID "LABELONE"
326 #define LVM2LABEL_SCAN_SECTORS 4
327 static int probe_lvm2(struct volume_id *id, __u64 off)
329 struct lvm2_super_block {
335 } __attribute__((packed)) *lvm;
340 buf = get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
345 for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
346 lvm = (struct lvm2_super_block *) &buf[soff];
348 if (strncmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
355 strncpy(id->type_version, lvm->type, 8);
356 id->usage_id = VOLUME_ID_RAID;
357 id->type_id = VOLUME_ID_LVM2;
358 id->type = "LVM2_member";
363 #define MD_RESERVED_BYTES 0x10000
364 #define MD_MAGIC 0xa92b4efc
365 static int probe_linux_raid(struct volume_id *id, __u64 off, __u64 size)
367 struct mdp_super_block {
380 __u32 not_persistent;
384 } __attribute__((packed)) *mdp;
393 sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
394 buf = get_buffer(id, off + sboff, 0x800);
398 mdp = (struct mdp_super_block *) buf;
400 if (le32_to_cpu(mdp->md_magic) != MD_MAGIC)
403 memcpy(uuid, &mdp->set_uuid0, 4);
404 memcpy(&uuid[4], &mdp->set_uuid1, 12);
405 set_uuid(id, uuid, UUID_DCE);
407 snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1, "%u.%u.%u",
408 le32_to_cpu(mdp->major_version),
409 le32_to_cpu(mdp->minor_version),
410 le32_to_cpu(mdp->patch_version));
412 dbg("found raid signature");
413 id->usage_id = VOLUME_ID_RAID;
414 id->type = "linux_raid_member";
419 #define MSDOS_MAGIC "\x55\xaa"
420 #define MSDOS_PARTTABLE_OFFSET 0x1be
421 #define MSDOS_SIG_OFF 0x1fe
423 #define DOS_EXTENDED_PARTITION 0x05
424 #define LINUX_EXTENDED_PARTITION 0x85
425 #define WIN98_EXTENDED_PARTITION 0x0f
426 #define LINUX_RAID_PARTITION 0xfd
427 #define is_extended(type) \
428 (type == DOS_EXTENDED_PARTITION || \
429 type == WIN98_EXTENDED_PARTITION || \
430 type == LINUX_EXTENDED_PARTITION)
431 #define is_raid(type) \
432 (type == LINUX_RAID_PARTITION)
433 static int probe_msdos_part_table(struct volume_id *id, __u64 off)
435 struct msdos_partition_entry {
446 } __attribute__((packed)) *part;
457 struct volume_id_partition *p;
459 buf = get_buffer(id, off, 0x200);
463 if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
466 /* check flags on all entries for a valid partition table */
467 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
468 for (i = 0; i < 4; i++) {
469 if (part[i].boot_ind != 0 &&
470 part[i].boot_ind != 0x80)
473 if (le32_to_cpu(part[i].nr_sects) != 0)
479 if (id->partitions != NULL)
480 free(id->partitions);
481 id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX *
482 sizeof(struct volume_id_partition));
483 if (id->partitions == NULL)
485 memset(id->partitions, 0x00,
486 VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition));
488 for (i = 0; i < 4; i++) {
489 poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
490 plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
495 p = &id->partitions[i];
497 p->partition_type_raw = part[i].sys_ind;
499 if (is_extended(part[i].sys_ind)) {
500 dbg("found extended partition at 0x%llx", poff);
501 p->usage_id = VOLUME_ID_PARTITIONTABLE;
502 p->type_id = VOLUME_ID_MSDOSEXTENDED;
503 p->type = "msdos_extended_partition";
505 extended = off + poff;
507 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
508 part[i].sys_ind, poff, plen);
510 if (is_raid(part[i].sys_ind))
511 p->usage_id = VOLUME_ID_RAID;
513 p->usage_id = VOLUME_ID_UNPROBED;
518 id->partition_count = i+1;
525 /* follow extended partition chain and add data partitions */
528 dbg("extended chain limit reached");
532 buf = get_buffer(id, current, 0x200);
536 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
538 if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
543 for (i = 0; i < 4; i++) {
544 poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
545 plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
550 if (is_extended(part[i].sys_ind)) {
551 dbg("found extended partition at 0x%llx", poff);
553 next = extended + poff;
555 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
556 part[i].sys_ind, poff, plen);
558 /* we always start at the 5th entry */
559 while (id->partition_count < 4)
560 id->partitions[id->partition_count++].usage_id =
563 p = &id->partitions[id->partition_count];
565 if (is_raid(part[i].sys_ind))
566 p->usage_id = VOLUME_ID_RAID;
568 p->usage_id = VOLUME_ID_UNPROBED;
570 p->off = current + poff;
572 id->partition_count++;
574 p->partition_type_raw = part[i].sys_ind;
576 if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
577 dbg("too many partitions");
586 id->usage_id = VOLUME_ID_PARTITIONTABLE;
587 id->type_id = VOLUME_ID_MSDOSPARTTABLE;
588 id->type = "msdos_partition_table";
593 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
594 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
595 #define EXT_SUPERBLOCK_OFFSET 0x400
596 static int probe_ext(struct volume_id *id, __u64 off)
598 struct ext2_super_block {
601 __u32 r_blocks_count;
602 __u32 free_blocks_count;
603 __u32 free_inodes_count;
604 __u32 first_data_block;
605 __u32 log_block_size;
610 __u32 feature_compat;
611 __u32 feature_incompat;
612 __u32 feature_ro_compat;
614 __u8 volume_name[16];
615 } __attribute__((__packed__)) *es;
617 es = (struct ext2_super_block *)
618 get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
622 if (es->magic[0] != 0123 ||
623 es->magic[1] != 0357)
626 set_label_raw(id, es->volume_name, 16);
627 set_label_string(id, es->volume_name, 16);
628 set_uuid(id, es->uuid, UUID_DCE);
630 if ((le32_to_cpu(es->feature_compat) &
631 EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
632 id->usage_id = VOLUME_ID_FILESYSTEM;
633 id->type_id = VOLUME_ID_EXT3;
636 id->usage_id = VOLUME_ID_FILESYSTEM;
637 id->type_id = VOLUME_ID_EXT2;
644 #define REISERFS1_SUPERBLOCK_OFFSET 0x2000
645 #define REISERFS_SUPERBLOCK_OFFSET 0x10000
646 static int probe_reiserfs(struct volume_id *id, __u64 off)
648 struct reiserfs_super_block {
654 __u32 orig_journal_size;
662 } __attribute__((__packed__)) *rs;
664 rs = (struct reiserfs_super_block *)
665 get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
669 if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0) {
670 strcpy(id->type_version, "3.6");
674 if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0) {
675 strcpy(id->type_version, "JR");
679 rs = (struct reiserfs_super_block *)
680 get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
684 if (strncmp(rs->magic, "ReIsErFs", 8) == 0) {
685 strcpy(id->type_version, "3.5");
692 set_label_raw(id, rs->label, 16);
693 set_label_string(id, rs->label, 16);
694 set_uuid(id, rs->uuid, UUID_DCE);
696 id->usage_id = VOLUME_ID_FILESYSTEM;
697 id->type_id = VOLUME_ID_REISERFS;
698 id->type = "reiserfs";
703 static int probe_xfs(struct volume_id *id, __u64 off)
705 struct xfs_super_block {
718 } __attribute__((__packed__)) *xs;
720 xs = (struct xfs_super_block *) get_buffer(id, off, 0x200);
724 if (strncmp(xs->magic, "XFSB", 4) != 0)
727 set_label_raw(id, xs->fname, 12);
728 set_label_string(id, xs->fname, 12);
729 set_uuid(id, xs->uuid, UUID_DCE);
731 id->usage_id = VOLUME_ID_FILESYSTEM;
732 id->type_id = VOLUME_ID_XFS;
738 #define JFS_SUPERBLOCK_OFFSET 0x8000
739 static int probe_jfs(struct volume_id *id, __u64 off)
741 struct jfs_super_block {
752 } __attribute__((__packed__)) *js;
754 js = (struct jfs_super_block *)
755 get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
759 if (strncmp(js->magic, "JFS1", 4) != 0)
762 set_label_raw(id, js->label, 16);
763 set_label_string(id, js->label, 16);
764 set_uuid(id, js->uuid, UUID_DCE);
766 id->usage_id = VOLUME_ID_FILESYSTEM;
767 id->type_id = VOLUME_ID_JFS;
773 #define FAT12_MAX 0xff5
774 #define FAT16_MAX 0xfff5
775 #define FAT_ATTR_VOLUME_ID 0x08
776 #define FAT_ATTR_DIR 0x10
777 #define FAT_ATTR_LONG_NAME 0x0f
778 #define FAT_ATTR_MASK 0x3f
779 #define FAT_ENTRY_FREE 0xe5
780 static int probe_vfat(struct volume_id *id, __u64 off)
782 struct vfat_super_block {
786 __u8 sectors_per_cluster;
798 struct fat_super_block {
805 } __attribute__((__packed__)) fat;
806 struct fat32_super_block {
820 } __attribute__((__packed__)) fat32;
821 } __attribute__((__packed__)) type;
822 } __attribute__((__packed__)) *vs;
824 struct vfat_dir_entry {
836 } __attribute__((__packed__)) *dir;
848 __u32 start_data_sect;
849 __u16 root_dir_entries;
857 vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
861 /* believe only that's fat, don't trust the version
862 * the cluster_count will tell us
864 if (strncmp(vs->sysid, "NTFS", 4) == 0)
867 if (strncmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
870 if (strncmp(vs->type.fat32.magic, "FAT32 ", 8) == 0)
873 if (strncmp(vs->type.fat.magic, "FAT16 ", 8) == 0)
876 if (strncmp(vs->type.fat.magic, "MSDOS", 5) == 0)
879 if (strncmp(vs->type.fat.magic, "FAT12 ", 8) == 0)
883 * There are old floppies out there without a magic, so we check
884 * for well known values and guess if it's a fat volume
887 /* boot jump address check */
888 if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
889 vs->boot_jump[0] != 0xe9)
896 /* cluster size check*/
897 if (vs->sectors_per_cluster == 0 ||
898 (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
902 if (vs->media < 0xf8 && vs->media != 0xf0)
910 /* sector size check */
911 sector_size = le16_to_cpu(vs->sector_size);
912 if (sector_size != 0x200 && sector_size != 0x400 &&
913 sector_size != 0x800 && sector_size != 0x1000)
916 dbg("sector_size 0x%x", sector_size);
917 dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
919 dir_entries = le16_to_cpu(vs->dir_entries);
920 reserved = le16_to_cpu(vs->reserved);
921 dbg("reserved 0x%x", reserved);
923 sect_count = le16_to_cpu(vs->sectors);
925 sect_count = le32_to_cpu(vs->total_sect);
926 dbg("sect_count 0x%x", sect_count);
928 fat_length = le16_to_cpu(vs->fat_length);
930 fat_length = le32_to_cpu(vs->type.fat32.fat32_length);
931 dbg("fat_length 0x%x", fat_length);
933 fat_size = fat_length * vs->fats;
934 dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
935 (sector_size-1)) / sector_size;
936 dbg("dir_size 0x%x", dir_size);
938 cluster_count = sect_count - (reserved + fat_size + dir_size);
939 cluster_count /= vs->sectors_per_cluster;
940 dbg("cluster_count 0x%x", cluster_count);
942 if (cluster_count < FAT12_MAX) {
943 strcpy(id->type_version, "FAT12");
944 } else if (cluster_count < FAT16_MAX) {
945 strcpy(id->type_version, "FAT16");
947 strcpy(id->type_version, "FAT32");
951 /* the label may be an attribute in the root directory */
952 root_start = (reserved + fat_size) * sector_size;
953 dbg("root dir start 0x%llx", root_start);
954 root_dir_entries = le16_to_cpu(vs->dir_entries);
955 dbg("expected entries 0x%x", root_dir_entries);
957 buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
958 buf = get_buffer(id, off + root_start, buf_size);
962 dir = (struct vfat_dir_entry*) buf;
964 for (i = 0; i < root_dir_entries; i++) {
966 if (dir[i].name[0] == 0x00) {
972 if (dir[i].name[0] == FAT_ENTRY_FREE)
976 if ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)
979 if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
980 /* labels do not have file data */
981 if (dir[i].cluster_high != 0 || dir[i].cluster_low != 0)
984 dbg("found ATTR_VOLUME_ID id in root dir");
989 dbg("skip dir entry");
992 vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
996 if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
997 set_label_raw(id, label, 11);
998 set_label_string(id, label, 11);
999 } else if (strncmp(vs->type.fat.label, "NO NAME ", 11) != 0) {
1000 set_label_raw(id, vs->type.fat.label, 11);
1001 set_label_string(id, vs->type.fat.label, 11);
1003 set_uuid(id, vs->type.fat.serno, UUID_DOS);
1007 /* FAT32 root dir is a cluster chain like any other directory */
1008 buf_size = vs->sectors_per_cluster * sector_size;
1009 root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
1010 dbg("root dir cluster %u", root_cluster);
1011 start_data_sect = reserved + fat_size;
1013 next = root_cluster;
1016 __u32 next_sect_off;
1018 __u64 fat_entry_off;
1021 dbg("next cluster %u", next);
1022 next_sect_off = (next - 2) * vs->sectors_per_cluster;
1023 next_off = (start_data_sect + next_sect_off) * sector_size;
1024 dbg("cluster offset 0x%llx", next_off);
1027 buf = get_buffer(id, off + next_off, buf_size);
1031 dir = (struct vfat_dir_entry*) buf;
1032 count = buf_size / sizeof(struct vfat_dir_entry);
1033 dbg("expected entries 0x%x", count);
1035 for (i = 0; i < count; i++) {
1037 if (dir[i].name[0] == 0x00) {
1043 if (dir[i].name[0] == FAT_ENTRY_FREE)
1047 if ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)
1050 if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
1051 /* labels do not have file data */
1052 if (dir[i].cluster_high != 0 || dir[i].cluster_low != 0)
1055 dbg("found ATTR_VOLUME_ID id in root dir");
1056 label = dir[i].name;
1060 dbg("skip dir entry");
1064 fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
1065 buf = get_buffer(id, off + fat_entry_off, buf_size);
1069 /* set next cluster */
1070 next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
1075 dbg("reached maximum follow count of root cluster chain, give up");
1078 vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
1082 if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
1083 set_label_raw(id, label, 11);
1084 set_label_string(id, label, 11);
1085 } else if (strncmp(vs->type.fat32.label, "NO NAME ", 11) != 0) {
1086 set_label_raw(id, vs->type.fat32.label, 11);
1087 set_label_string(id, vs->type.fat32.label, 11);
1089 set_uuid(id, vs->type.fat32.serno, UUID_DOS);
1092 id->usage_id = VOLUME_ID_FILESYSTEM;
1093 id->type_id = VOLUME_ID_VFAT;
1099 #define UDF_VSD_OFFSET 0x8000
1100 static int probe_udf(struct volume_id *id, __u64 off)
1102 struct volume_descriptor {
1103 struct descriptor_tag {
1112 } __attribute__((__packed__)) tag;
1114 struct anchor_descriptor {
1117 } __attribute__((__packed__)) anchor;
1118 struct primary_descriptor {
1124 } __attribute__((__packed__)) ident;
1125 } __attribute__((__packed__)) primary;
1126 } __attribute__((__packed__)) type;
1127 } __attribute__((__packed__)) *vd;
1129 struct volume_structure_descriptor {
1142 vsd = (struct volume_structure_descriptor *)
1143 get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
1147 if (strncmp(vsd->id, "NSR02", 5) == 0)
1149 if (strncmp(vsd->id, "NSR03", 5) == 0)
1151 if (strncmp(vsd->id, "BEA01", 5) == 0)
1153 if (strncmp(vsd->id, "BOOT2", 5) == 0)
1155 if (strncmp(vsd->id, "CD001", 5) == 0)
1157 if (strncmp(vsd->id, "CDW02", 5) == 0)
1159 if (strncmp(vsd->id, "TEA03", 5) == 0)
1164 /* search the next VSD to get the logical block size of the volume */
1165 for (bs = 0x800; bs < 0x8000; bs += 0x800) {
1166 vsd = (struct volume_structure_descriptor *)
1167 get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
1170 dbg("test for blocksize: 0x%x", bs);
1171 if (vsd->id[0] != '\0')
1177 /* search the list of VSDs for a NSR descriptor */
1178 for (b = 0; b < 64; b++) {
1179 vsd = (struct volume_structure_descriptor *)
1180 get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
1184 dbg("vsd: %c%c%c%c%c",
1185 vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
1187 if (vsd->id[0] == '\0')
1189 if (strncmp(vsd->id, "NSR02", 5) == 0)
1191 if (strncmp(vsd->id, "NSR03", 5) == 0)
1197 /* read anchor volume descriptor */
1198 vd = (struct volume_descriptor *)
1199 get_buffer(id, off + (256 * bs), 0x200);
1203 type = le16_to_cpu(vd->tag.id);
1204 if (type != 2) /* TAG_ID_AVDP */
1207 /* get desriptor list address and block count */
1208 count = le32_to_cpu(vd->type.anchor.length) / bs;
1209 loc = le32_to_cpu(vd->type.anchor.location);
1210 dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
1212 /* pick the primary descriptor from the list */
1213 for (b = 0; b < count; b++) {
1214 vd = (struct volume_descriptor *)
1215 get_buffer(id, off + ((loc + b) * bs), 0x200);
1219 type = le16_to_cpu(vd->tag.id);
1220 dbg("descriptor type %i", type);
1222 /* check validity */
1225 if (le32_to_cpu(vd->tag.location) != loc + b)
1228 if (type == 1) /* TAG_ID_PVD */
1234 set_label_raw(id, &(vd->type.primary.ident.clen), 32);
1236 clen = vd->type.primary.ident.clen;
1237 dbg("label string charsize=%i bit", clen);
1239 set_label_string(id, vd->type.primary.ident.c, 31);
1240 else if (clen == 16)
1241 set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
1244 id->usage_id = VOLUME_ID_FILESYSTEM;
1245 id->type_id = VOLUME_ID_UDF;
1251 #define ISO_SUPERBLOCK_OFFSET 0x8000
1252 #define ISO_SECTOR_SIZE 0x800
1253 #define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
1254 #define ISO_VD_PRIMARY 0x1
1255 #define ISO_VD_SUPPLEMENTARY 0x2
1256 #define ISO_VD_END 0xff
1257 #define ISO_VD_MAX 16
1258 static int probe_iso9660(struct volume_id *id, __u64 off)
1260 union iso_super_block {
1268 } __attribute__((__packed__)) iso;
1274 } __attribute__((__packed__)) hs;
1275 } __attribute__((__packed__)) *is;
1277 is = (union iso_super_block *)
1278 get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
1282 if (strncmp(is->iso.id, "CD001", 5) == 0) {
1283 char root_label[VOLUME_ID_LABEL_SIZE+1];
1288 memset(root_label, 0, sizeof(root_label));
1289 strncpy(root_label, is->iso.volume_id, sizeof(root_label)-1);
1292 vd_offset = ISO_VD_OFFSET;
1293 for (i = 0; i < ISO_VD_MAX; i++) {
1294 is = (union iso_super_block *)
1295 get_buffer (id, off + vd_offset, 0x200);
1296 if (is == NULL || is->iso.type == ISO_VD_END)
1298 if (is->iso.type == ISO_VD_SUPPLEMENTARY) {
1299 dbg("found ISO supplementary VD at offset 0x%llx", off + vd_offset);
1300 set_label_raw(id, is->iso.volume_id, 32);
1301 set_label_unicode16(id, is->iso.volume_id, BE, 32);
1305 vd_offset += ISO_SECTOR_SIZE;
1309 (found_svd && !strncmp(root_label, id->label, 16)))
1311 set_label_raw(id, root_label, 32);
1312 set_label_string(id, root_label, 32);
1316 if (strncmp(is->hs.id, "CDROM", 5) == 0)
1321 id->usage_id = VOLUME_ID_FILESYSTEM;
1322 id->type_id = VOLUME_ID_ISO9660;
1323 id->type = "iso9660";
1328 #define UFS_MAGIC 0x00011954
1329 #define UFS2_MAGIC 0x19540119
1330 #define UFS_MAGIC_FEA 0x00195612
1331 #define UFS_MAGIC_LFN 0x00095014
1334 static int probe_ufs(struct volume_id *id, __u64 off)
1336 struct ufs_super_block {
1370 __u32 fs_npsect_state;
1371 __u32 fs_interleave;
1389 } __attribute__((__packed__)) fs_cstotal;
1399 __u32 fs_maxcluster;
1401 __u16 fs_opostbl[16][8];
1402 } __attribute__((__packed__)) fs_u1;
1405 __u8 fs_volname[32];
1410 __u32 fs_contigdirs;
1412 __u32 fs_maxcluster;
1416 __s64 fs_sparecon64[17];
1418 struct ufs2_csum_total {
1423 __u64 cs_numclusters;
1425 } __attribute__((__packed__)) fs_cstotal;
1426 struct ufs_timeval {
1429 } __attribute__((__packed__)) fs_time;
1433 __s64 fs_pendingblocks;
1434 __s32 fs_pendinginodes;
1435 } __attribute__((__packed__)) fs_u2;
1439 __s32 fs_sparecon[53];
1441 __s32 fs_sparecon2[1];
1445 } __attribute__((__packed__)) fs_sun;
1447 __s32 fs_sparecon[53];
1449 __s32 fs_sparecon2[1];
1453 } __attribute__((__packed__)) fs_sunx86;
1455 __s32 fs_sparecon[50];
1456 __s32 fs_contigsumsize;
1457 __s32 fs_maxsymlinklen;
1459 __u32 fs_maxfilesize[2];
1463 } __attribute__((__packed__)) fs_44;
1465 __s32 fs_postblformat;
1471 } __attribute__((__packed__)) *ufs;
1475 int offsets[] = {0, 8, 64, 256, -1};
1477 for (i = 0; offsets[i] >= 0; i++) {
1478 ufs = (struct ufs_super_block *)
1479 get_buffer(id, off + (offsets[i] * 0x400), 0x800);
1483 dbg("offset 0x%x", offsets[i] * 0x400);
1484 magic = be32_to_cpu(ufs->fs_magic);
1485 if ((magic == UFS_MAGIC) ||
1486 (magic == UFS2_MAGIC) ||
1487 (magic == UFS_MAGIC_FEA) ||
1488 (magic == UFS_MAGIC_LFN)) {
1489 dbg("magic 0x%08x(be)", magic);
1492 magic = le32_to_cpu(ufs->fs_magic);
1493 if ((magic == UFS_MAGIC) ||
1494 (magic == UFS2_MAGIC) ||
1495 (magic == UFS_MAGIC_FEA) ||
1496 (magic == UFS_MAGIC_LFN)) {
1497 dbg("magic 0x%08x(le)", magic);
1504 id->usage_id = VOLUME_ID_FILESYSTEM;
1505 id->type_id = VOLUME_ID_UFS;
1511 static int probe_mac_partition_map(struct volume_id *id, __u64 off)
1513 struct mac_driver_desc {
1517 } __attribute__((__packed__)) *driver;
1519 struct mac_partition {
1527 } __attribute__((__packed__)) *part;
1531 buf = get_buffer(id, off, 0x200);
1535 part = (struct mac_partition *) buf;
1536 if ((strncmp(part->signature, "PM", 2) == 0) &&
1537 (strncmp(part->type, "Apple_partition_map", 19) == 0)) {
1538 /* linux creates an own subdevice for the map
1539 * just return the type if the drive header is missing */
1540 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1541 id->type_id = VOLUME_ID_MACPARTMAP;
1542 id->type = "mac_partition_map";
1546 driver = (struct mac_driver_desc *) buf;
1547 if (strncmp(driver->signature, "ER", 2) == 0) {
1548 /* we are on a main device, like a CD
1549 * just try to probe the first partition from the map */
1550 unsigned int bsize = be16_to_cpu(driver->block_size);
1554 /* get first entry of partition table */
1555 buf = get_buffer(id, off + bsize, 0x200);
1559 part = (struct mac_partition *) buf;
1560 if (strncmp(part->signature, "PM", 2) != 0)
1563 part_count = be32_to_cpu(part->map_count);
1564 dbg("expecting %d partition entries", part_count);
1566 if (id->partitions != NULL)
1567 free(id->partitions);
1569 malloc(part_count * sizeof(struct volume_id_partition));
1570 if (id->partitions == NULL)
1572 memset(id->partitions, 0x00, sizeof(struct volume_id_partition));
1574 id->partition_count = part_count;
1576 for (i = 0; i < part_count; i++) {
1580 buf = get_buffer(id, off + ((i+1) * bsize), 0x200);
1584 part = (struct mac_partition *) buf;
1585 if (strncmp(part->signature, "PM", 2) != 0)
1588 poff = be32_to_cpu(part->start_block) * bsize;
1589 plen = be32_to_cpu(part->block_count) * bsize;
1590 dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
1591 part->type, poff, plen);
1593 id->partitions[i].off = poff;
1594 id->partitions[i].len = plen;
1596 if (strncmp(part->type, "Apple_Free", 10) == 0) {
1597 id->partitions[i].usage_id = VOLUME_ID_UNUSED;
1598 } else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
1599 id->partitions[i].usage_id = VOLUME_ID_PARTITIONTABLE;
1600 id->partitions[i].type_id = VOLUME_ID_MACPARTMAP;
1602 id->partitions[i].usage_id = VOLUME_ID_UNPROBED;
1605 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1606 id->type_id = VOLUME_ID_MACPARTMAP;
1607 id->type = "mac_partition_map";
1614 #define HFS_SUPERBLOCK_OFFSET 0x400
1615 #define HFS_NODE_LEAF 0xff
1616 #define HFSPLUS_POR_CNID 1
1617 #define HFSPLUS_EXTENT_COUNT 8
1618 static int probe_hfs_hfsplus(struct volume_id *id, __u64 off)
1620 struct hfs_finder_info{
1628 } __attribute__((__packed__));
1649 __u32 xt_clump_size;
1650 __u32 ct_clump_size;
1651 __u16 num_root_dirs;
1654 struct hfs_finder_info finder_info;
1656 __u16 embed_startblock;
1657 __u16 embed_blockcount;
1658 } __attribute__((__packed__)) *hfs;
1660 struct hfsplus_bnode_descriptor {
1667 } __attribute__((__packed__));
1669 struct hfsplus_bheader_record {
1676 } __attribute__((__packed__));
1678 struct hfsplus_catalog_key {
1682 __u8 unicode[255 * 2];
1683 } __attribute__((__packed__));
1685 struct hfsplus_extent {
1688 } __attribute__((__packed__));
1690 struct hfsplus_fork {
1694 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1695 } __attribute__((__packed__));
1697 struct hfsplus_vol_header {
1701 __u32 last_mount_vers;
1713 __u32 rsrc_clump_sz;
1714 __u32 data_clump_sz;
1717 __u64 encodings_bmp;
1718 struct hfs_finder_info finder_info;
1719 struct hfsplus_fork alloc_file;
1720 struct hfsplus_fork ext_file;
1721 struct hfsplus_fork cat_file;
1722 struct hfsplus_fork attr_file;
1723 struct hfsplus_fork start_file;
1724 } __attribute__((__packed__)) *hfsplus;
1726 unsigned int blocksize;
1727 unsigned int cat_block;
1728 unsigned int ext_block_start;
1729 unsigned int ext_block_count;
1731 unsigned int leaf_node_head;
1732 unsigned int leaf_node_count;
1733 unsigned int leaf_node_size;
1734 unsigned int leaf_block;
1736 unsigned int alloc_block_size;
1737 unsigned int alloc_first_block;
1738 unsigned int embed_first_block;
1739 unsigned int record_count;
1740 struct hfsplus_bnode_descriptor *descr;
1741 struct hfsplus_bheader_record *bnode;
1742 struct hfsplus_catalog_key *key;
1743 unsigned int label_len;
1744 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1747 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1751 hfs = (struct hfs_mdb *) buf;
1752 if (strncmp(hfs->signature, "BD", 2) != 0)
1755 /* it may be just a hfs wrapper for hfs+ */
1756 if (strncmp(hfs->embed_sig, "H+", 2) == 0) {
1757 alloc_block_size = be32_to_cpu(hfs->al_blk_size);
1758 dbg("alloc_block_size 0x%x", alloc_block_size);
1760 alloc_first_block = be16_to_cpu(hfs->al_bl_st);
1761 dbg("alloc_first_block 0x%x", alloc_first_block);
1763 embed_first_block = be16_to_cpu(hfs->embed_startblock);
1764 dbg("embed_first_block 0x%x", embed_first_block);
1766 off += (alloc_first_block * 512) +
1767 (embed_first_block * alloc_block_size);
1768 dbg("hfs wrapped hfs+ found at offset 0x%llx", off);
1770 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1776 if (hfs->label_len > 0 && hfs->label_len < 28) {
1777 set_label_raw(id, hfs->label, hfs->label_len);
1778 set_label_string(id, hfs->label, hfs->label_len) ;
1781 set_uuid(id, hfs->finder_info.id, UUID_HFS);
1783 id->usage_id = VOLUME_ID_FILESYSTEM;
1784 id->type_id = VOLUME_ID_HFS;
1790 hfsplus = (struct hfsplus_vol_header *) buf;
1791 if (strncmp(hfsplus->signature, "H+", 2) == 0)
1793 if (strncmp(hfsplus->signature, "HX", 2) == 0)
1798 set_uuid(id, hfsplus->finder_info.id, UUID_HFS);
1800 blocksize = be32_to_cpu(hfsplus->blocksize);
1801 dbg("blocksize %u", blocksize);
1803 memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
1804 cat_block = be32_to_cpu(extents[0].start_block);
1805 dbg("catalog start block 0x%x", cat_block);
1807 buf = get_buffer(id, off + (cat_block * blocksize), 0x2000);
1811 bnode = (struct hfsplus_bheader_record *)
1812 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1814 leaf_node_head = be32_to_cpu(bnode->leaf_head);
1815 dbg("catalog leaf node 0x%x", leaf_node_head);
1817 leaf_node_size = be16_to_cpu(bnode->node_size);
1818 dbg("leaf node size 0x%x", leaf_node_size);
1820 leaf_node_count = be32_to_cpu(bnode->leaf_count);
1821 dbg("leaf node count 0x%x", leaf_node_count);
1822 if (leaf_node_count == 0)
1825 leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
1827 /* get physical location */
1828 for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
1829 ext_block_start = be32_to_cpu(extents[ext].start_block);
1830 ext_block_count = be32_to_cpu(extents[ext].block_count);
1831 dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
1833 if (ext_block_count == 0)
1836 /* this is our extent */
1837 if (leaf_block < ext_block_count)
1840 leaf_block -= ext_block_count;
1842 if (ext == HFSPLUS_EXTENT_COUNT)
1844 dbg("found block in extent %i", ext);
1846 leaf_off = (ext_block_start + leaf_block) * blocksize;
1848 buf = get_buffer(id, off + leaf_off, leaf_node_size);
1852 descr = (struct hfsplus_bnode_descriptor *) buf;
1853 dbg("descriptor type 0x%x", descr->type);
1855 record_count = be16_to_cpu(descr->num_recs);
1856 dbg("number of records %u", record_count);
1857 if (record_count == 0)
1860 if (descr->type != HFS_NODE_LEAF)
1863 key = (struct hfsplus_catalog_key *)
1864 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1866 dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
1867 if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
1870 label_len = be16_to_cpu(key->unicode_len) * 2;
1871 dbg("label unicode16 len %i", label_len);
1872 set_label_raw(id, key->unicode, label_len);
1873 set_label_unicode16(id, key->unicode, BE, label_len);
1876 id->usage_id = VOLUME_ID_FILESYSTEM;
1877 id->type_id = VOLUME_ID_HFSPLUS;
1878 id->type = "hfsplus";
1883 #define MFT_RECORD_VOLUME 3
1884 #define MFT_RECORD_ATTR_VOLUME_NAME 0x60
1885 #define MFT_RECORD_ATTR_VOLUME_INFO 0x70
1886 #define MFT_RECORD_ATTR_OBJECT_ID 0x40
1887 #define MFT_RECORD_ATTR_END 0xffffffffu
1888 static int probe_ntfs(struct volume_id *id, __u64 off)
1890 struct ntfs_super_block {
1893 __u16 bytes_per_sector;
1894 __u8 sectors_per_cluster;
1895 __u16 reserved_sectors;
1900 __u16 sectors_per_fat;
1901 __u16 sectors_per_track;
1903 __u32 hidden_sectors;
1904 __u32 large_sectors;
1906 __u64 number_of_sectors;
1907 __u64 mft_cluster_location;
1908 __u64 mft_mirror_cluster_location;
1909 __s8 cluster_per_mft_record;
1911 __s8 cluster_per_index_record;
1913 __u8 volume_serial[8];
1915 } __attribute__((__packed__)) *ns;
1917 struct master_file_table_record {
1922 __u16 sequence_number;
1927 __u32 bytes_allocated;
1928 } __attribute__((__packed__)) *mftr;
1930 struct file_attribute {
1940 } __attribute__((__packed__)) *attr;
1942 struct volume_info {
1946 } __attribute__((__packed__)) *info;
1948 unsigned int sector_size;
1949 unsigned int cluster_size;
1952 unsigned int mft_record_size;
1953 unsigned int attr_type;
1954 unsigned int attr_off;
1955 unsigned int attr_len;
1956 unsigned int val_off;
1957 unsigned int val_len;
1961 ns = (struct ntfs_super_block *) get_buffer(id, off, 0x200);
1965 if (strncmp(ns->oem_id, "NTFS", 4) != 0)
1968 set_uuid(id, ns->volume_serial, UUID_NTFS);
1970 sector_size = le16_to_cpu(ns->bytes_per_sector);
1971 cluster_size = ns->sectors_per_cluster * sector_size;
1972 mft_cluster = le64_to_cpu(ns->mft_cluster_location);
1973 mft_off = mft_cluster * cluster_size;
1975 if (ns->cluster_per_mft_record < 0)
1976 /* size = -log2(mft_record_size); normally 1024 Bytes */
1977 mft_record_size = 1 << -ns->cluster_per_mft_record;
1979 mft_record_size = ns->cluster_per_mft_record * cluster_size;
1981 dbg("sectorsize 0x%x", sector_size);
1982 dbg("clustersize 0x%x", cluster_size);
1983 dbg("mftcluster %lli", mft_cluster);
1984 dbg("mftoffset 0x%llx", mft_off);
1985 dbg("cluster per mft_record %i", ns->cluster_per_mft_record);
1986 dbg("mft record size %i", mft_record_size);
1988 buf = get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
1993 mftr = (struct master_file_table_record*) buf;
1995 dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
1996 if (strncmp(mftr->magic, "FILE", 4) != 0)
1999 attr_off = le16_to_cpu(mftr->attrs_offset);
2000 dbg("file $Volume's attributes are at offset %i", attr_off);
2003 attr = (struct file_attribute*) &buf[attr_off];
2004 attr_type = le32_to_cpu(attr->type);
2005 attr_len = le16_to_cpu(attr->len);
2006 val_off = le16_to_cpu(attr->value_offset);
2007 val_len = le32_to_cpu(attr->value_len);
2008 attr_off += attr_len;
2013 if (attr_off >= mft_record_size)
2016 if (attr_type == MFT_RECORD_ATTR_END)
2019 dbg("found attribute type 0x%x, len %i, at offset %i",
2020 attr_type, attr_len, attr_off);
2022 if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
2023 dbg("found info, len %i", val_len);
2024 info = (struct volume_info*) (((__u8 *) attr) + val_off);
2025 snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1,
2026 "%u.%u", info->major_ver, info->minor_ver);
2029 if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
2030 dbg("found label, len %i", val_len);
2031 if (val_len > VOLUME_ID_LABEL_SIZE)
2032 val_len = VOLUME_ID_LABEL_SIZE;
2034 val = ((__u8 *) attr) + val_off;
2035 set_label_raw(id, val, val_len);
2036 set_label_unicode16(id, val, LE, val_len);
2041 id->usage_id = VOLUME_ID_FILESYSTEM;
2042 id->type_id = VOLUME_ID_NTFS;
2048 #define LARGEST_PAGESIZE 0x4000
2049 static int probe_swap(struct volume_id *id, __u64 off)
2051 struct swap_header_v1_2 {
2052 __u8 bootbits[1024];
2057 __u8 volume_name[16];
2058 } __attribute__((__packed__)) *sw;
2063 /* the swap signature is at the end of the PAGE_SIZE */
2064 for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
2065 buf = get_buffer(id, off + page-10, 10);
2069 if (strncmp(buf, "SWAP-SPACE", 10) == 0) {
2070 strcpy(id->type_version, "1");
2074 if (strncmp(buf, "SWAPSPACE2", 10) == 0) {
2075 sw = (struct swap_header_v1_2 *) get_buffer(id, off, sizeof(struct swap_header_v1_2));
2078 strcpy(id->type_version, "2");
2079 set_label_raw(id, sw->volume_name, 16);
2080 set_label_string(id, sw->volume_name, 16);
2081 set_uuid(id, sw->uuid, UUID_DCE);
2088 id->usage_id = VOLUME_ID_OTHER;
2089 id->type_id = VOLUME_ID_SWAP;
2095 /* probe volume for filesystem type and try to read label+uuid */
2096 int volume_id_probe(struct volume_id *id,
2097 enum volume_id_type type,
2098 unsigned long long off,
2099 unsigned long long size)
2103 dbg("called with size=0x%llx", size);
2109 case VOLUME_ID_MSDOSPARTTABLE:
2110 rc = probe_msdos_part_table(id, off);
2112 case VOLUME_ID_EXT3:
2113 case VOLUME_ID_EXT2:
2114 rc = probe_ext(id, off);
2116 case VOLUME_ID_REISERFS:
2117 rc = probe_reiserfs(id, off);
2120 rc = probe_xfs(id, off);
2123 rc = probe_jfs(id, off);
2125 case VOLUME_ID_VFAT:
2126 rc = probe_vfat(id, off);
2129 rc = probe_udf(id, off);
2131 case VOLUME_ID_ISO9660:
2132 rc = probe_iso9660(id, off);
2134 case VOLUME_ID_MACPARTMAP:
2135 rc = probe_mac_partition_map(id, off);
2138 case VOLUME_ID_HFSPLUS:
2139 rc = probe_hfs_hfsplus(id, off);
2142 rc = probe_ufs(id, off);
2144 case VOLUME_ID_NTFS:
2145 rc = probe_ntfs(id, off);
2147 case VOLUME_ID_SWAP:
2148 rc = probe_swap(id, off);
2150 case VOLUME_ID_LINUX_RAID:
2151 rc = probe_linux_raid(id, off, size);
2153 case VOLUME_ID_LVM1:
2154 rc = probe_lvm1(id, off);
2156 case VOLUME_ID_LVM2:
2157 rc = probe_lvm2(id, off);
2159 case VOLUME_ID_HPTRAID:
2160 rc = probe_highpoint_ataraid(id, off);
2164 /* probe for raid first, cause fs probes may be successful on raid members */
2165 rc = probe_linux_raid(id, off, size);
2168 rc = probe_lvm1(id, off);
2171 rc = probe_lvm2(id, off);
2174 rc = probe_highpoint_ataraid(id, off);
2178 /* signature in the first block, only small buffer needed */
2179 rc = probe_vfat(id, off);
2182 rc = probe_mac_partition_map(id, off);
2185 rc = probe_xfs(id, off);
2189 /* fill buffer with maximum */
2190 get_buffer(id, 0, SB_BUFFER_SIZE);
2192 rc = probe_swap(id, off);
2195 rc = probe_ext(id, off);
2198 rc = probe_reiserfs(id, off);
2201 rc = probe_jfs(id, off);
2204 rc = probe_udf(id, off);
2207 rc = probe_iso9660(id, off);
2210 rc = probe_hfs_hfsplus(id, off);
2213 rc = probe_ufs(id, off);
2216 rc = probe_ntfs(id, off);
2223 /* If the filestystem in recognized, we free the allocated buffers,
2224 otherwise they will stay in place for the possible next probe call */
2231 /* open volume by already open file descriptor */
2232 struct volume_id *volume_id_open_fd(int fd)
2234 struct volume_id *id;
2236 id = malloc(sizeof(struct volume_id));
2239 memset(id, 0x00, sizeof(struct volume_id));
2246 /* open volume by device node */
2247 struct volume_id *volume_id_open_node(const char *path)
2249 struct volume_id *id;
2252 fd = open(path, O_RDONLY);
2254 dbg("unable to open '%s'", path);
2258 id = volume_id_open_fd(fd);
2262 /* close fd on device close */
2268 /* open volume by major/minor */
2269 struct volume_id *volume_id_open_dev_t(dev_t devt)
2271 struct volume_id *id;
2272 __u8 tmp_node[VOLUME_ID_PATH_MAX];
2274 snprintf(tmp_node, VOLUME_ID_PATH_MAX,
2275 "/tmp/volume-%u-%u-%u", getpid(), major(devt), minor(devt));
2276 tmp_node[VOLUME_ID_PATH_MAX] = '\0';
2278 /* create tempory node to open the block device */
2280 if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0)
2283 id = volume_id_open_node(tmp_node);
2290 /* free allocated volume info */
2291 void volume_id_close(struct volume_id *id)
2296 if (id->fd_close != 0)
2301 if (id->partitions != NULL)
2302 free(id->partitions);