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_ENTRY_FREE 0xe5
778 static int probe_vfat(struct volume_id *id, __u64 off)
780 struct vfat_super_block {
784 __u8 sectors_per_cluster;
796 struct fat_super_block {
803 } __attribute__((__packed__)) fat;
804 struct fat32_super_block {
818 } __attribute__((__packed__)) fat32;
819 } __attribute__((__packed__)) type;
820 } __attribute__((__packed__)) *vs;
822 struct vfat_dir_entry {
834 } __attribute__((__packed__)) *dir;
846 __u32 start_data_sect;
847 __u16 root_dir_entries;
855 vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
859 /* believe only that's fat, don't trust the version
860 * the cluster_count will tell us
862 if (strncmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
865 if (strncmp(vs->type.fat32.magic, "FAT32 ", 8) == 0)
868 if (strncmp(vs->type.fat.magic, "FAT16 ", 8) == 0)
871 if (strncmp(vs->type.fat.magic, "MSDOS", 5) == 0)
874 if (strncmp(vs->type.fat.magic, "FAT12 ", 8) == 0)
878 * There are old floppies out there without a magic, so we check
879 * for well known values and guess if it's a fat volume
882 /* boot jump address check */
883 if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
884 vs->boot_jump[0] != 0xe9)
891 /* cluster size check*/
892 if (vs->sectors_per_cluster == 0 ||
893 (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
897 if (vs->media < 0xf8 && vs->media != 0xf0)
905 /* sector size check */
906 sector_size = le16_to_cpu(vs->sector_size);
907 if (sector_size != 0x200 && sector_size != 0x400 &&
908 sector_size != 0x800 && sector_size != 0x1000)
911 dbg("sector_size 0x%x", sector_size);
912 dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
914 dir_entries = le16_to_cpu(vs->dir_entries);
915 reserved = le16_to_cpu(vs->reserved);
916 dbg("reserved 0x%x", reserved);
918 sect_count = le16_to_cpu(vs->sectors);
920 sect_count = le32_to_cpu(vs->total_sect);
921 dbg("sect_count 0x%x", sect_count);
923 fat_length = le16_to_cpu(vs->fat_length);
925 fat_length = le32_to_cpu(vs->type.fat32.fat32_length);
926 dbg("fat_length 0x%x", fat_length);
928 fat_size = fat_length * vs->fats;
929 dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
930 (sector_size-1)) / sector_size;
931 dbg("dir_size 0x%x", dir_size);
933 cluster_count = sect_count - (reserved + fat_size + dir_size);
934 cluster_count /= vs->sectors_per_cluster;
935 dbg("cluster_count 0x%x", cluster_count);
937 if (cluster_count < FAT12_MAX) {
938 strcpy(id->type_version, "FAT12");
939 } else if (cluster_count < FAT16_MAX) {
940 strcpy(id->type_version, "FAT16");
942 strcpy(id->type_version, "FAT32");
946 /* the label may be an attribute in the root directory */
947 root_start = (reserved + fat_size) * sector_size;
948 dbg("root dir start 0x%llx", root_start);
949 root_dir_entries = le16_to_cpu(vs->dir_entries);
950 dbg("expected entries 0x%x", root_dir_entries);
952 buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
953 buf = get_buffer(id, off + root_start, buf_size);
957 dir = (struct vfat_dir_entry*) buf;
959 for (i = 0; i <= root_dir_entries; i++) {
961 if (dir[i].name[0] == 0x00) {
967 if (dir[i].name[0] == FAT_ENTRY_FREE)
970 if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
971 dbg("found ATTR_VOLUME_ID id in root dir");
976 dbg("skip dir entry");
979 if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
980 set_label_raw(id, label, 11);
981 set_label_string(id, label, 11);
982 } else if (strncmp(vs->type.fat.label, "NO NAME ", 11) != 0) {
983 set_label_raw(id, vs->type.fat.label, 11);
984 set_label_string(id, vs->type.fat.label, 11);
986 set_uuid(id, vs->type.fat.serno, UUID_DOS);
990 /* FAT32 root dir is a cluster chain like any other directory */
991 buf_size = vs->sectors_per_cluster * sector_size;
992 root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
993 dbg("root dir cluster %u", root_cluster);
994 start_data_sect = reserved + fat_size;
1001 __u64 fat_entry_off;
1004 dbg("next cluster %u", next);
1005 next_sect_off = (next - 2) * vs->sectors_per_cluster;
1006 next_off = (start_data_sect + next_sect_off) * sector_size;
1007 dbg("cluster offset 0x%llx", next_off);
1010 buf = get_buffer(id, off + next_off, buf_size);
1014 dir = (struct vfat_dir_entry*) buf;
1015 count = buf_size / sizeof(struct vfat_dir_entry);
1016 dbg("expected entries 0x%x", count);
1018 for (i = 0; i <= count; i++) {
1020 if (dir[i].name[0] == 0x00) {
1026 if (dir[i].name[0] == FAT_ENTRY_FREE)
1029 if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
1030 dbg("found ATTR_VOLUME_ID id in root dir");
1031 label = dir[i].name;
1035 dbg("skip dir entry");
1039 fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
1040 buf = get_buffer(id, off + fat_entry_off, buf_size);
1044 /* set next cluster */
1045 next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
1050 dbg("reached maximum follow count of root cluster chain, give up");
1053 if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
1054 set_label_raw(id, label, 11);
1055 set_label_string(id, label, 11);
1056 } else if (strncmp(vs->type.fat32.label, "NO NAME ", 11) != 0) {
1057 set_label_raw(id, vs->type.fat32.label, 11);
1058 set_label_string(id, vs->type.fat32.label, 11);
1060 set_uuid(id, vs->type.fat32.serno, UUID_DOS);
1063 id->usage_id = VOLUME_ID_FILESYSTEM;
1064 id->type_id = VOLUME_ID_VFAT;
1070 #define UDF_VSD_OFFSET 0x8000
1071 static int probe_udf(struct volume_id *id, __u64 off)
1073 struct volume_descriptor {
1074 struct descriptor_tag {
1083 } __attribute__((__packed__)) tag;
1085 struct anchor_descriptor {
1088 } __attribute__((__packed__)) anchor;
1089 struct primary_descriptor {
1095 } __attribute__((__packed__)) ident;
1096 } __attribute__((__packed__)) primary;
1097 } __attribute__((__packed__)) type;
1098 } __attribute__((__packed__)) *vd;
1100 struct volume_structure_descriptor {
1113 vsd = (struct volume_structure_descriptor *)
1114 get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
1118 if (strncmp(vsd->id, "NSR02", 5) == 0)
1120 if (strncmp(vsd->id, "NSR03", 5) == 0)
1122 if (strncmp(vsd->id, "BEA01", 5) == 0)
1124 if (strncmp(vsd->id, "BOOT2", 5) == 0)
1126 if (strncmp(vsd->id, "CD001", 5) == 0)
1128 if (strncmp(vsd->id, "CDW02", 5) == 0)
1130 if (strncmp(vsd->id, "TEA03", 5) == 0)
1135 /* search the next VSD to get the logical block size of the volume */
1136 for (bs = 0x800; bs < 0x8000; bs += 0x800) {
1137 vsd = (struct volume_structure_descriptor *)
1138 get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
1141 dbg("test for blocksize: 0x%x", bs);
1142 if (vsd->id[0] != '\0')
1148 /* search the list of VSDs for a NSR descriptor */
1149 for (b = 0; b < 64; b++) {
1150 vsd = (struct volume_structure_descriptor *)
1151 get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
1155 dbg("vsd: %c%c%c%c%c",
1156 vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
1158 if (vsd->id[0] == '\0')
1160 if (strncmp(vsd->id, "NSR02", 5) == 0)
1162 if (strncmp(vsd->id, "NSR03", 5) == 0)
1168 /* read anchor volume descriptor */
1169 vd = (struct volume_descriptor *)
1170 get_buffer(id, off + (256 * bs), 0x200);
1174 type = le16_to_cpu(vd->tag.id);
1175 if (type != 2) /* TAG_ID_AVDP */
1178 /* get desriptor list address and block count */
1179 count = le32_to_cpu(vd->type.anchor.length) / bs;
1180 loc = le32_to_cpu(vd->type.anchor.location);
1181 dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
1183 /* pick the primary descriptor from the list */
1184 for (b = 0; b < count; b++) {
1185 vd = (struct volume_descriptor *)
1186 get_buffer(id, off + ((loc + b) * bs), 0x200);
1190 type = le16_to_cpu(vd->tag.id);
1191 dbg("descriptor type %i", type);
1193 /* check validity */
1196 if (le32_to_cpu(vd->tag.location) != loc + b)
1199 if (type == 1) /* TAG_ID_PVD */
1205 set_label_raw(id, &(vd->type.primary.ident.clen), 32);
1207 clen = vd->type.primary.ident.clen;
1208 dbg("label string charsize=%i bit", clen);
1210 set_label_string(id, vd->type.primary.ident.c, 31);
1211 else if (clen == 16)
1212 set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
1215 id->usage_id = VOLUME_ID_FILESYSTEM;
1216 id->type_id = VOLUME_ID_UDF;
1222 #define ISO_SUPERBLOCK_OFFSET 0x8000
1223 #define ISO_SECTOR_SIZE 0x800
1224 #define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
1225 #define ISO_VD_PRIMARY 0x1
1226 #define ISO_VD_SUPPLEMENTARY 0x2
1227 #define ISO_VD_END 0xff
1228 #define ISO_VD_MAX 16
1229 static int probe_iso9660(struct volume_id *id, __u64 off)
1231 union iso_super_block {
1239 } __attribute__((__packed__)) iso;
1245 } __attribute__((__packed__)) hs;
1246 } __attribute__((__packed__)) *is;
1248 is = (union iso_super_block *)
1249 get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
1253 if (strncmp(is->iso.id, "CD001", 5) == 0) {
1259 vd_offset = ISO_VD_OFFSET;
1260 for (i = 0; i < ISO_VD_MAX; i++) {
1261 is = (union iso_super_block *)
1262 get_buffer (id, off + vd_offset, 0x200);
1263 if (is == NULL || is->iso.type == ISO_VD_END)
1265 if (is->iso.type == ISO_VD_SUPPLEMENTARY) {
1266 dbg("found ISO supplementary VD at offset 0x%llx", off + vd_offset);
1270 vd_offset += ISO_SECTOR_SIZE;
1274 is = (union iso_super_block *)
1275 get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
1278 set_label_raw(id, is->iso.volume_id, 32);
1279 set_label_string(id, is->iso.volume_id, 32);
1281 set_label_raw(id, is->iso.volume_id, 32);
1282 set_label_unicode16(id, is->iso.volume_id, BE, 32);
1286 if (strncmp(is->hs.id, "CDROM", 5) == 0)
1291 id->usage_id = VOLUME_ID_FILESYSTEM;
1292 id->type_id = VOLUME_ID_ISO9660;
1293 id->type = "iso9660";
1298 #define UFS_MAGIC 0x00011954
1299 #define UFS2_MAGIC 0x19540119
1300 #define UFS_MAGIC_FEA 0x00195612
1301 #define UFS_MAGIC_LFN 0x00095014
1304 static int probe_ufs(struct volume_id *id, __u64 off)
1306 struct ufs_super_block {
1340 __u32 fs_npsect_state;
1341 __u32 fs_interleave;
1359 } __attribute__((__packed__)) fs_cstotal;
1369 __u32 fs_maxcluster;
1371 __u16 fs_opostbl[16][8];
1372 } __attribute__((__packed__)) fs_u1;
1375 __u8 fs_volname[32];
1380 __u32 fs_contigdirs;
1382 __u32 fs_maxcluster;
1386 __s64 fs_sparecon64[17];
1388 struct ufs2_csum_total {
1393 __u64 cs_numclusters;
1395 } __attribute__((__packed__)) fs_cstotal;
1396 struct ufs_timeval {
1399 } __attribute__((__packed__)) fs_time;
1403 __s64 fs_pendingblocks;
1404 __s32 fs_pendinginodes;
1405 } __attribute__((__packed__)) fs_u2;
1409 __s32 fs_sparecon[53];
1411 __s32 fs_sparecon2[1];
1415 } __attribute__((__packed__)) fs_sun;
1417 __s32 fs_sparecon[53];
1419 __s32 fs_sparecon2[1];
1423 } __attribute__((__packed__)) fs_sunx86;
1425 __s32 fs_sparecon[50];
1426 __s32 fs_contigsumsize;
1427 __s32 fs_maxsymlinklen;
1429 __u32 fs_maxfilesize[2];
1433 } __attribute__((__packed__)) fs_44;
1435 __s32 fs_postblformat;
1441 } __attribute__((__packed__)) *ufs;
1445 int offsets[] = {0, 8, 64, 256, -1};
1447 for (i = 0; offsets[i] >= 0; i++) {
1448 ufs = (struct ufs_super_block *)
1449 get_buffer(id, off + (offsets[i] * 0x400), 0x800);
1453 dbg("offset 0x%x", offsets[i] * 0x400);
1454 magic = be32_to_cpu(ufs->fs_magic);
1455 if ((magic == UFS_MAGIC) ||
1456 (magic == UFS2_MAGIC) ||
1457 (magic == UFS_MAGIC_FEA) ||
1458 (magic == UFS_MAGIC_LFN)) {
1459 dbg("magic 0x%08x(be)", magic);
1462 magic = le32_to_cpu(ufs->fs_magic);
1463 if ((magic == UFS_MAGIC) ||
1464 (magic == UFS2_MAGIC) ||
1465 (magic == UFS_MAGIC_FEA) ||
1466 (magic == UFS_MAGIC_LFN)) {
1467 dbg("magic 0x%08x(le)", magic);
1474 id->usage_id = VOLUME_ID_FILESYSTEM;
1475 id->type_id = VOLUME_ID_UFS;
1481 static int probe_mac_partition_map(struct volume_id *id, __u64 off)
1483 struct mac_driver_desc {
1487 } __attribute__((__packed__)) *driver;
1489 struct mac_partition {
1497 } __attribute__((__packed__)) *part;
1501 buf = get_buffer(id, off, 0x200);
1505 part = (struct mac_partition *) buf;
1506 if ((strncmp(part->signature, "PM", 2) == 0) &&
1507 (strncmp(part->type, "Apple_partition_map", 19) == 0)) {
1508 /* linux creates an own subdevice for the map
1509 * just return the type if the drive header is missing */
1510 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1511 id->type_id = VOLUME_ID_MACPARTMAP;
1512 id->type = "mac_partition_map";
1516 driver = (struct mac_driver_desc *) buf;
1517 if (strncmp(driver->signature, "ER", 2) == 0) {
1518 /* we are on a main device, like a CD
1519 * just try to probe the first partition from the map */
1520 unsigned int bsize = be16_to_cpu(driver->block_size);
1524 /* get first entry of partition table */
1525 buf = get_buffer(id, off + bsize, 0x200);
1529 part = (struct mac_partition *) buf;
1530 if (strncmp(part->signature, "PM", 2) != 0)
1533 part_count = be32_to_cpu(part->map_count);
1534 dbg("expecting %d partition entries", part_count);
1536 if (id->partitions != NULL)
1537 free(id->partitions);
1539 malloc(part_count * sizeof(struct volume_id_partition));
1540 if (id->partitions == NULL)
1542 memset(id->partitions, 0x00, sizeof(struct volume_id_partition));
1544 id->partition_count = part_count;
1546 for (i = 0; i < part_count; i++) {
1550 buf = get_buffer(id, off + ((i+1) * bsize), 0x200);
1554 part = (struct mac_partition *) buf;
1555 if (strncmp(part->signature, "PM", 2) != 0)
1558 poff = be32_to_cpu(part->start_block) * bsize;
1559 plen = be32_to_cpu(part->block_count) * bsize;
1560 dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
1561 part->type, poff, plen);
1563 id->partitions[i].off = poff;
1564 id->partitions[i].len = plen;
1566 if (strncmp(part->type, "Apple_Free", 10) == 0) {
1567 id->partitions[i].usage_id = VOLUME_ID_UNUSED;
1568 } else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
1569 id->partitions[i].usage_id = VOLUME_ID_PARTITIONTABLE;
1570 id->partitions[i].type_id = VOLUME_ID_MACPARTMAP;
1572 id->partitions[i].usage_id = VOLUME_ID_UNPROBED;
1575 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1576 id->type_id = VOLUME_ID_MACPARTMAP;
1577 id->type = "mac_partition_map";
1584 #define HFS_SUPERBLOCK_OFFSET 0x400
1585 #define HFS_NODE_LEAF 0xff
1586 #define HFSPLUS_POR_CNID 1
1587 #define HFSPLUS_EXTENT_COUNT 8
1588 static int probe_hfs_hfsplus(struct volume_id *id, __u64 off)
1590 struct hfs_finder_info{
1598 } __attribute__((__packed__));
1619 __u32 xt_clump_size;
1620 __u32 ct_clump_size;
1621 __u16 num_root_dirs;
1624 struct hfs_finder_info finder_info;
1626 __u16 embed_startblock;
1627 __u16 embed_blockcount;
1628 } __attribute__((__packed__)) *hfs;
1630 struct hfsplus_bnode_descriptor {
1637 } __attribute__((__packed__));
1639 struct hfsplus_bheader_record {
1646 } __attribute__((__packed__));
1648 struct hfsplus_catalog_key {
1652 __u8 unicode[255 * 2];
1653 } __attribute__((__packed__));
1655 struct hfsplus_extent {
1658 } __attribute__((__packed__));
1660 struct hfsplus_fork {
1664 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1665 } __attribute__((__packed__));
1667 struct hfsplus_vol_header {
1671 __u32 last_mount_vers;
1683 __u32 rsrc_clump_sz;
1684 __u32 data_clump_sz;
1687 __u64 encodings_bmp;
1688 struct hfs_finder_info finder_info;
1689 struct hfsplus_fork alloc_file;
1690 struct hfsplus_fork ext_file;
1691 struct hfsplus_fork cat_file;
1692 struct hfsplus_fork attr_file;
1693 struct hfsplus_fork start_file;
1694 } __attribute__((__packed__)) *hfsplus;
1696 unsigned int blocksize;
1697 unsigned int cat_block;
1698 unsigned int ext_block_start;
1699 unsigned int ext_block_count;
1701 unsigned int leaf_node_head;
1702 unsigned int leaf_node_count;
1703 unsigned int leaf_node_size;
1704 unsigned int leaf_block;
1706 unsigned int alloc_block_size;
1707 unsigned int alloc_first_block;
1708 unsigned int embed_first_block;
1709 unsigned int record_count;
1710 struct hfsplus_bnode_descriptor *descr;
1711 struct hfsplus_bheader_record *bnode;
1712 struct hfsplus_catalog_key *key;
1713 unsigned int label_len;
1714 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1717 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1721 hfs = (struct hfs_mdb *) buf;
1722 if (strncmp(hfs->signature, "BD", 2) != 0)
1725 /* it may be just a hfs wrapper for hfs+ */
1726 if (strncmp(hfs->embed_sig, "H+", 2) == 0) {
1727 alloc_block_size = be32_to_cpu(hfs->al_blk_size);
1728 dbg("alloc_block_size 0x%x", alloc_block_size);
1730 alloc_first_block = be16_to_cpu(hfs->al_bl_st);
1731 dbg("alloc_first_block 0x%x", alloc_first_block);
1733 embed_first_block = be16_to_cpu(hfs->embed_startblock);
1734 dbg("embed_first_block 0x%x", embed_first_block);
1736 off += (alloc_first_block * 512) +
1737 (embed_first_block * alloc_block_size);
1738 dbg("hfs wrapped hfs+ found at offset 0x%llx", off);
1740 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1746 if (hfs->label_len > 0 && hfs->label_len < 28) {
1747 set_label_raw(id, hfs->label, hfs->label_len);
1748 set_label_string(id, hfs->label, hfs->label_len) ;
1751 set_uuid(id, hfs->finder_info.id, UUID_HFS);
1753 id->usage_id = VOLUME_ID_FILESYSTEM;
1754 id->type_id = VOLUME_ID_HFS;
1760 hfsplus = (struct hfsplus_vol_header *) buf;
1761 if (strncmp(hfsplus->signature, "H+", 2) == 0)
1763 if (strncmp(hfsplus->signature, "HX", 2) == 0)
1768 set_uuid(id, hfsplus->finder_info.id, UUID_HFS);
1770 blocksize = be32_to_cpu(hfsplus->blocksize);
1771 dbg("blocksize %u", blocksize);
1773 memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
1774 cat_block = be32_to_cpu(extents[0].start_block);
1775 dbg("catalog start block 0x%x", cat_block);
1777 buf = get_buffer(id, off + (cat_block * blocksize), 0x2000);
1781 bnode = (struct hfsplus_bheader_record *)
1782 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1784 leaf_node_head = be32_to_cpu(bnode->leaf_head);
1785 dbg("catalog leaf node 0x%x", leaf_node_head);
1787 leaf_node_size = be16_to_cpu(bnode->node_size);
1788 dbg("leaf node size 0x%x", leaf_node_size);
1790 leaf_node_count = be32_to_cpu(bnode->leaf_count);
1791 dbg("leaf node count 0x%x", leaf_node_count);
1792 if (leaf_node_count == 0)
1795 leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
1797 /* get physical location */
1798 for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
1799 ext_block_start = be32_to_cpu(extents[ext].start_block);
1800 ext_block_count = be32_to_cpu(extents[ext].block_count);
1801 dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
1803 if (ext_block_count == 0)
1806 /* this is our extent */
1807 if (leaf_block < ext_block_count)
1810 leaf_block -= ext_block_count;
1812 if (ext == HFSPLUS_EXTENT_COUNT)
1814 dbg("found block in extent %i", ext);
1816 leaf_off = (ext_block_start + leaf_block) * blocksize;
1818 buf = get_buffer(id, off + leaf_off, leaf_node_size);
1822 descr = (struct hfsplus_bnode_descriptor *) buf;
1823 dbg("descriptor type 0x%x", descr->type);
1825 record_count = be16_to_cpu(descr->num_recs);
1826 dbg("number of records %u", record_count);
1827 if (record_count == 0)
1830 if (descr->type != HFS_NODE_LEAF)
1833 key = (struct hfsplus_catalog_key *)
1834 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1836 dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
1837 if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
1840 label_len = be16_to_cpu(key->unicode_len) * 2;
1841 dbg("label unicode16 len %i", label_len);
1842 set_label_raw(id, key->unicode, label_len);
1843 set_label_unicode16(id, key->unicode, BE, label_len);
1846 id->usage_id = VOLUME_ID_FILESYSTEM;
1847 id->type_id = VOLUME_ID_HFSPLUS;
1848 id->type = "hfsplus";
1853 #define MFT_RECORD_VOLUME 3
1854 #define MFT_RECORD_ATTR_VOLUME_NAME 0x60
1855 #define MFT_RECORD_ATTR_VOLUME_INFO 0x70
1856 #define MFT_RECORD_ATTR_OBJECT_ID 0x40
1857 #define MFT_RECORD_ATTR_END 0xffffffffu
1858 static int probe_ntfs(struct volume_id *id, __u64 off)
1860 struct ntfs_super_block {
1863 __u16 bytes_per_sector;
1864 __u8 sectors_per_cluster;
1865 __u16 reserved_sectors;
1870 __u16 sectors_per_fat;
1871 __u16 sectors_per_track;
1873 __u32 hidden_sectors;
1874 __u32 large_sectors;
1876 __u64 number_of_sectors;
1877 __u64 mft_cluster_location;
1878 __u64 mft_mirror_cluster_location;
1879 __s8 cluster_per_mft_record;
1881 __s8 cluster_per_index_record;
1883 __u8 volume_serial[8];
1885 } __attribute__((__packed__)) *ns;
1887 struct master_file_table_record {
1892 __u16 sequence_number;
1897 __u32 bytes_allocated;
1898 } __attribute__((__packed__)) *mftr;
1900 struct file_attribute {
1910 } __attribute__((__packed__)) *attr;
1912 struct volume_info {
1916 } __attribute__((__packed__)) *info;
1918 unsigned int sector_size;
1919 unsigned int cluster_size;
1922 unsigned int mft_record_size;
1923 unsigned int attr_type;
1924 unsigned int attr_off;
1925 unsigned int attr_len;
1926 unsigned int val_off;
1927 unsigned int val_len;
1931 ns = (struct ntfs_super_block *) get_buffer(id, off, 0x200);
1935 if (strncmp(ns->oem_id, "NTFS", 4) != 0)
1938 set_uuid(id, ns->volume_serial, UUID_NTFS);
1940 sector_size = le16_to_cpu(ns->bytes_per_sector);
1941 cluster_size = ns->sectors_per_cluster * sector_size;
1942 mft_cluster = le64_to_cpu(ns->mft_cluster_location);
1943 mft_off = mft_cluster * cluster_size;
1945 if (ns->cluster_per_mft_record < 0)
1946 /* size = -log2(mft_record_size); normally 1024 Bytes */
1947 mft_record_size = 1 << -ns->cluster_per_mft_record;
1949 mft_record_size = ns->cluster_per_mft_record * cluster_size;
1951 dbg("sectorsize 0x%x", sector_size);
1952 dbg("clustersize 0x%x", cluster_size);
1953 dbg("mftcluster %lli", mft_cluster);
1954 dbg("mftoffset 0x%llx", mft_off);
1955 dbg("cluster per mft_record %i", ns->cluster_per_mft_record);
1956 dbg("mft record size %i", mft_record_size);
1958 buf = get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
1963 mftr = (struct master_file_table_record*) buf;
1965 dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
1966 if (strncmp(mftr->magic, "FILE", 4) != 0)
1969 attr_off = le16_to_cpu(mftr->attrs_offset);
1970 dbg("file $Volume's attributes are at offset %i", attr_off);
1973 attr = (struct file_attribute*) &buf[attr_off];
1974 attr_type = le32_to_cpu(attr->type);
1975 attr_len = le16_to_cpu(attr->len);
1976 val_off = le16_to_cpu(attr->value_offset);
1977 val_len = le32_to_cpu(attr->value_len);
1978 attr_off += attr_len;
1983 if (attr_off >= mft_record_size)
1986 if (attr_type == MFT_RECORD_ATTR_END)
1989 dbg("found attribute type 0x%x, len %i, at offset %i",
1990 attr_type, attr_len, attr_off);
1992 if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
1993 dbg("found info, len %i", val_len);
1994 info = (struct volume_info*) (((__u8 *) attr) + val_off);
1995 snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1,
1996 "%u.%u", info->major_ver, info->minor_ver);
1999 if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
2000 dbg("found label, len %i", val_len);
2001 if (val_len > VOLUME_ID_LABEL_SIZE)
2002 val_len = VOLUME_ID_LABEL_SIZE;
2004 val = ((__u8 *) attr) + val_off;
2005 set_label_raw(id, val, val_len);
2006 set_label_unicode16(id, val, LE, val_len);
2011 id->usage_id = VOLUME_ID_FILESYSTEM;
2012 id->type_id = VOLUME_ID_NTFS;
2018 #define LARGEST_PAGESIZE 0x4000
2019 static int probe_swap(struct volume_id *id, __u64 off)
2021 struct swap_header_v1_2 {
2022 __u8 bootbits[1024];
2027 __u8 volume_name[16];
2028 } __attribute__((__packed__)) *sw;
2033 /* the swap signature is at the end of the PAGE_SIZE */
2034 for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
2035 buf = get_buffer(id, off + page-10, 10);
2039 if (strncmp(buf, "SWAP-SPACE", 10) == 0) {
2040 strcpy(id->type_version, "1");
2044 if (strncmp(buf, "SWAPSPACE2", 10) == 0) {
2045 sw = (struct swap_header_v1_2 *) get_buffer(id, off, sizeof(struct swap_header_v1_2));
2048 strcpy(id->type_version, "2");
2049 set_label_raw(id, sw->volume_name, 16);
2050 set_label_string(id, sw->volume_name, 16);
2051 set_uuid(id, sw->uuid, UUID_DCE);
2058 id->usage_id = VOLUME_ID_OTHER;
2059 id->type_id = VOLUME_ID_SWAP;
2065 /* probe volume for filesystem type and try to read label+uuid */
2066 int volume_id_probe(struct volume_id *id,
2067 enum volume_id_type type,
2068 unsigned long long off,
2069 unsigned long long size)
2073 dbg("called with size=0x%llx", size);
2079 case VOLUME_ID_MSDOSPARTTABLE:
2080 rc = probe_msdos_part_table(id, off);
2082 case VOLUME_ID_EXT3:
2083 case VOLUME_ID_EXT2:
2084 rc = probe_ext(id, off);
2086 case VOLUME_ID_REISERFS:
2087 rc = probe_reiserfs(id, off);
2090 rc = probe_xfs(id, off);
2093 rc = probe_jfs(id, off);
2095 case VOLUME_ID_VFAT:
2096 rc = probe_vfat(id, off);
2099 rc = probe_udf(id, off);
2101 case VOLUME_ID_ISO9660:
2102 rc = probe_iso9660(id, off);
2104 case VOLUME_ID_MACPARTMAP:
2105 rc = probe_mac_partition_map(id, off);
2108 case VOLUME_ID_HFSPLUS:
2109 rc = probe_hfs_hfsplus(id, off);
2112 rc = probe_ufs(id, off);
2114 case VOLUME_ID_NTFS:
2115 rc = probe_ntfs(id, off);
2117 case VOLUME_ID_SWAP:
2118 rc = probe_swap(id, off);
2120 case VOLUME_ID_LINUX_RAID:
2121 rc = probe_linux_raid(id, off, size);
2123 case VOLUME_ID_LVM1:
2124 rc = probe_lvm1(id, off);
2126 case VOLUME_ID_LVM2:
2127 rc = probe_lvm2(id, off);
2129 case VOLUME_ID_HPTRAID:
2130 rc = probe_highpoint_ataraid(id, off);
2134 /* probe for raid first, cause fs probes may be successful on raid members */
2135 rc = probe_linux_raid(id, off, size);
2138 rc = probe_lvm1(id, off);
2141 rc = probe_lvm2(id, off);
2144 rc = probe_highpoint_ataraid(id, off);
2148 /* signature in the first block, only small buffer needed */
2149 rc = probe_vfat(id, off);
2152 rc = probe_mac_partition_map(id, off);
2155 rc = probe_xfs(id, off);
2159 /* fill buffer with maximum */
2160 get_buffer(id, 0, SB_BUFFER_SIZE);
2162 rc = probe_swap(id, off);
2165 rc = probe_ext(id, off);
2168 rc = probe_reiserfs(id, off);
2171 rc = probe_jfs(id, off);
2174 rc = probe_udf(id, off);
2177 rc = probe_iso9660(id, off);
2180 rc = probe_hfs_hfsplus(id, off);
2183 rc = probe_ufs(id, off);
2186 rc = probe_ntfs(id, off);
2193 /* If the filestystem in recognized, we free the allocated buffers,
2194 otherwise they will stay in place for the possible next probe call */
2201 /* open volume by already open file descriptor */
2202 struct volume_id *volume_id_open_fd(int fd)
2204 struct volume_id *id;
2206 id = malloc(sizeof(struct volume_id));
2209 memset(id, 0x00, sizeof(struct volume_id));
2216 /* open volume by device node */
2217 struct volume_id *volume_id_open_node(const char *path)
2219 struct volume_id *id;
2222 fd = open(path, O_RDONLY);
2224 dbg("unable to open '%s'", path);
2228 id = volume_id_open_fd(fd);
2232 /* close fd on device close */
2238 /* open volume by major/minor */
2239 struct volume_id *volume_id_open_dev_t(dev_t devt)
2241 struct volume_id *id;
2242 __u8 tmp_node[VOLUME_ID_PATH_MAX];
2244 snprintf(tmp_node, VOLUME_ID_PATH_MAX,
2245 "/tmp/volume-%u-%u-%u", getpid(), major(devt), minor(devt));
2246 tmp_node[VOLUME_ID_PATH_MAX] = '\0';
2248 /* create tempory node to open the block device */
2250 if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0)
2253 id = volume_id_open_node(tmp_node);
2260 /* free allocated volume info */
2261 void volume_id_close(struct volume_id *id)
2266 if (id->fd_close != 0)
2271 if (id->partitions != NULL)
2272 free(id->partitions);