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 0x1000
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 len = SEEK_BUFFER_SIZE;
227 /* get seek buffer */
228 if (id->seekbuf == NULL) {
229 id->seekbuf = malloc(SEEK_BUFFER_SIZE);
230 if (id->seekbuf == NULL)
234 /* check if we need to read */
235 if ((off < id->seekbuf_off) ||
236 ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
237 dbg("read seekbuf off:0x%llx len:0x%x", off, len);
238 if (lseek(id->fd, off, SEEK_SET) == -1)
240 buf_len = read(id->fd, id->seekbuf, len);
241 dbg("got 0x%x (%i) bytes", buf_len, buf_len);
242 id->seekbuf_off = off;
243 id->seekbuf_len = buf_len;
248 return &(id->seekbuf[off - id->seekbuf_off]);
252 static void free_buffer(struct volume_id *id)
254 if (id->sbbuf != NULL) {
259 if (id->seekbuf != NULL) {
266 #define LVM1_SB_OFF 0x400
267 #define LVM1_MAGIC "HM"
268 static int probe_lvm1(struct volume_id *id, __u64 off)
270 struct lvm2_super_block {
272 } __attribute__((packed)) *lvm;
276 buf = get_buffer(id, off + LVM1_SB_OFF, 0x800);
280 lvm = (struct lvm2_super_block *) buf;
282 if (strncmp(lvm->id, LVM1_MAGIC, 2) != 0)
285 id->usage_id = VOLUME_ID_RAID;
286 id->type_id = VOLUME_ID_LVM1;
287 id->type = "LVM1_member";
292 #define LVM2_LABEL_ID "LABELONE"
293 #define LVM2LABEL_SCAN_SECTORS 4
294 static int probe_lvm2(struct volume_id *id, __u64 off)
296 struct lvm2_super_block {
302 } __attribute__((packed)) *lvm;
307 buf = get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
312 for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
313 lvm = (struct lvm2_super_block *) &buf[soff];
315 if (strncmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
322 strncpy(id->type_version, lvm->type, 8);
323 id->usage_id = VOLUME_ID_RAID;
324 id->type_id = VOLUME_ID_LVM1;
325 id->type = "LVM2_member";
330 #define MD_RESERVED_BYTES 0x10000
331 #define MD_MAGIC 0xa92b4efc
332 static int probe_linux_raid(struct volume_id *id, __u64 off, __u64 size)
334 struct mdp_super_block {
347 __u32 not_persistent;
351 } __attribute__((packed)) *mdp;
360 sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
361 buf = get_buffer(id, off + sboff, 0x800);
365 mdp = (struct mdp_super_block *) buf;
367 if (le32_to_cpu(mdp->md_magic) != MD_MAGIC)
370 memcpy(uuid, &mdp->set_uuid0, 4);
371 memcpy(&uuid[4], &mdp->set_uuid1, 12);
372 set_uuid(id, uuid, UUID_DCE);
374 snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1, "%u.%u.%u",
375 le32_to_cpu(mdp->major_version),
376 le32_to_cpu(mdp->minor_version),
377 le32_to_cpu(mdp->patch_version));
379 dbg("found raid signature");
380 id->usage_id = VOLUME_ID_RAID;
381 id->type = "linux_raid_member";
386 #define MSDOS_MAGIC "\x55\xaa"
387 #define MSDOS_PARTTABLE_OFFSET 0x1be
388 #define MSDOS_SIG_OFF 0x1fe
390 #define DOS_EXTENDED_PARTITION 0x05
391 #define LINUX_EXTENDED_PARTITION 0x85
392 #define WIN98_EXTENDED_PARTITION 0x0f
393 #define LINUX_RAID_PARTITION 0xfd
394 #define is_extended(type) \
395 (type == DOS_EXTENDED_PARTITION || \
396 type == WIN98_EXTENDED_PARTITION || \
397 type == LINUX_EXTENDED_PARTITION)
398 #define is_raid(type) \
399 (type == LINUX_RAID_PARTITION)
400 static int probe_msdos_part_table(struct volume_id *id, __u64 off)
402 struct msdos_partition_entry {
413 } __attribute__((packed)) *part;
424 struct volume_id_partition *p;
426 buf = get_buffer(id, off, 0x200);
430 if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
433 /* check flags on all entries for a valid partition table */
434 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
435 for (i = 0; i < 4; i++) {
436 if (part[i].boot_ind != 0 &&
437 part[i].boot_ind != 0x80)
440 if (le32_to_cpu(part[i].nr_sects) != 0)
446 if (id->partitions != NULL)
447 free(id->partitions);
448 id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX *
449 sizeof(struct volume_id_partition));
450 if (id->partitions == NULL)
452 memset(id->partitions, 0x00,
453 VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition));
455 for (i = 0; i < 4; i++) {
456 poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
457 plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
462 p = &id->partitions[i];
464 if (is_extended(part[i].sys_ind)) {
465 dbg("found extended partition at 0x%llx", poff);
466 p->usage_id = VOLUME_ID_PARTITIONTABLE;
467 p->type_id = VOLUME_ID_MSDOSEXTENDED;
468 p->type = "msdos_extended_partition";
470 extended = off + poff;
472 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
473 part[i].sys_ind, poff, plen);
475 if (is_raid(part[i].sys_ind))
476 p->usage_id = VOLUME_ID_RAID;
478 p->usage_id = VOLUME_ID_UNPROBED;
483 id->partition_count = i+1;
490 /* follow extended partition chain and add data partitions */
493 dbg("extended chain limit reached");
497 buf = get_buffer(id, current, 0x200);
501 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
503 if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
508 for (i = 0; i < 4; i++) {
509 poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
510 plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
515 if (is_extended(part[i].sys_ind)) {
516 dbg("found extended partition at 0x%llx", poff);
518 next = extended + poff;
520 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
521 part[i].sys_ind, poff, plen);
523 /* we always start at the 5th entry */
524 while (id->partition_count < 4)
525 id->partitions[id->partition_count++].usage_id =
528 p = &id->partitions[id->partition_count];
530 if (is_raid(part[i].sys_ind))
531 p->usage_id = VOLUME_ID_RAID;
533 p->usage_id = VOLUME_ID_UNPROBED;
535 p->off = current + poff;
537 id->partition_count++;
538 if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
539 dbg("to many partitions");
548 id->usage_id = VOLUME_ID_PARTITIONTABLE;
549 id->type_id = VOLUME_ID_MSDOSPARTTABLE;
550 id->type = "msdos_partition_table";
555 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
556 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
557 #define EXT_SUPERBLOCK_OFFSET 0x400
558 static int probe_ext(struct volume_id *id, __u64 off)
560 struct ext2_super_block {
563 __u32 r_blocks_count;
564 __u32 free_blocks_count;
565 __u32 free_inodes_count;
566 __u32 first_data_block;
567 __u32 log_block_size;
572 __u32 feature_compat;
573 __u32 feature_incompat;
574 __u32 feature_ro_compat;
576 __u8 volume_name[16];
577 } __attribute__((__packed__)) *es;
579 es = (struct ext2_super_block *)
580 get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
584 if (es->magic[0] != 0123 ||
585 es->magic[1] != 0357)
588 set_label_raw(id, es->volume_name, 16);
589 set_label_string(id, es->volume_name, 16);
590 set_uuid(id, es->uuid, UUID_DCE);
592 if ((le32_to_cpu(es->feature_compat) &
593 EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
594 id->usage_id = VOLUME_ID_FILESYSTEM;
595 id->type_id = VOLUME_ID_EXT3;
598 id->usage_id = VOLUME_ID_FILESYSTEM;
599 id->type_id = VOLUME_ID_EXT2;
606 #define REISERFS1_SUPERBLOCK_OFFSET 0x2000
607 #define REISERFS_SUPERBLOCK_OFFSET 0x10000
608 static int probe_reiserfs(struct volume_id *id, __u64 off)
610 struct reiserfs_super_block {
616 __u32 orig_journal_size;
624 } __attribute__((__packed__)) *rs;
626 rs = (struct reiserfs_super_block *)
627 get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
631 if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0) {
632 strcpy(id->type_version, "3.6");
636 if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0) {
637 strcpy(id->type_version, "JR");
641 rs = (struct reiserfs_super_block *)
642 get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
646 if (strncmp(rs->magic, "ReIsErFs", 8) == 0) {
647 strcpy(id->type_version, "3.5");
654 set_label_raw(id, rs->label, 16);
655 set_label_string(id, rs->label, 16);
656 set_uuid(id, rs->uuid, UUID_DCE);
658 id->usage_id = VOLUME_ID_FILESYSTEM;
659 id->type_id = VOLUME_ID_REISERFS;
660 id->type = "reiserfs";
665 static int probe_xfs(struct volume_id *id, __u64 off)
667 struct xfs_super_block {
680 } __attribute__((__packed__)) *xs;
682 xs = (struct xfs_super_block *) get_buffer(id, off, 0x200);
686 if (strncmp(xs->magic, "XFSB", 4) != 0)
689 set_label_raw(id, xs->fname, 12);
690 set_label_string(id, xs->fname, 12);
691 set_uuid(id, xs->uuid, UUID_DCE);
693 id->usage_id = VOLUME_ID_FILESYSTEM;
694 id->type_id = VOLUME_ID_XFS;
700 #define JFS_SUPERBLOCK_OFFSET 0x8000
701 static int probe_jfs(struct volume_id *id, __u64 off)
703 struct jfs_super_block {
714 } __attribute__((__packed__)) *js;
716 js = (struct jfs_super_block *)
717 get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
721 if (strncmp(js->magic, "JFS1", 4) != 0)
724 set_label_raw(id, js->label, 16);
725 set_label_string(id, js->label, 16);
726 set_uuid(id, js->uuid, UUID_DCE);
728 id->usage_id = VOLUME_ID_FILESYSTEM;
729 id->type_id = VOLUME_ID_JFS;
735 #define FAT12_MAX 0xff5
736 #define FAT16_MAX 0xfff5
737 #define FAT_ATTR_VOLUME 0x08
738 static int probe_vfat(struct volume_id *id, __u64 off)
740 struct vfat_super_block {
744 __u8 sectors_per_cluster;
756 struct fat_super_block {
763 } __attribute__((__packed__)) fat;
764 struct fat32_super_block {
778 } __attribute__((__packed__)) fat32;
779 } __attribute__((__packed__)) type;
780 } __attribute__((__packed__)) *vs;
782 struct vfat_dir_entry {
794 } __attribute__((__packed__)) *dir;
806 __u32 start_data_sect;
807 __u16 root_dir_entries;
815 vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
819 /* believe only that's fat, don't trust the version
820 * the cluster_count will tell us
822 if (strncmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
825 if (strncmp(vs->type.fat32.magic, "FAT32 ", 8) == 0)
828 if (strncmp(vs->type.fat.magic, "FAT16 ", 8) == 0)
831 if (strncmp(vs->type.fat.magic, "MSDOS", 5) == 0)
834 if (strncmp(vs->type.fat.magic, "FAT12 ", 8) == 0)
838 * There are old floppies out there without a magic, so we check
839 * for well known values and guess if it's a fat volume
842 /* boot jump address check */
843 if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
844 vs->boot_jump[0] != 0xe9)
851 /* cluster size check*/
852 if (vs->sectors_per_cluster == 0 ||
853 (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
857 if (vs->media < 0xf8 && vs->media != 0xf0)
865 /* sector size check */
866 sector_size = le16_to_cpu(vs->sector_size);
867 if (sector_size != 0x200 && sector_size != 0x400 &&
868 sector_size != 0x800 && sector_size != 0x1000)
871 dbg("sector_size 0x%x", sector_size);
872 dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
874 dir_entries = le16_to_cpu(vs->dir_entries);
875 reserved = le16_to_cpu(vs->reserved);
876 dbg("reserved 0x%x", reserved);
878 sect_count = le16_to_cpu(vs->sectors);
880 sect_count = le32_to_cpu(vs->total_sect);
881 dbg("sect_count 0x%x", sect_count);
883 fat_length = le16_to_cpu(vs->fat_length);
885 fat_length = le32_to_cpu(vs->type.fat32.fat32_length);
886 dbg("fat_length 0x%x", fat_length);
888 fat_size = fat_length * vs->fats;
889 dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
890 (sector_size-1)) / sector_size;
891 dbg("dir_size 0x%x", dir_size);
893 cluster_count = sect_count - (reserved + fat_size + dir_size);
894 cluster_count /= vs->sectors_per_cluster;
895 dbg("cluster_count 0x%x", cluster_count);
897 if (cluster_count < FAT12_MAX) {
898 strcpy(id->type_version, "FAT12");
899 } else if (cluster_count < FAT16_MAX) {
900 strcpy(id->type_version, "FAT16");
902 strcpy(id->type_version, "FAT32");
906 /* the label may be an attribute in the root directory */
907 root_start = (reserved + fat_size) * sector_size;
908 dbg("root dir start 0x%llx", root_start);
909 root_dir_entries = le16_to_cpu(vs->dir_entries);
910 dbg("expected entries 0x%x", root_dir_entries);
912 buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
913 buf = get_buffer(id, off + root_start, buf_size);
917 dir = (struct vfat_dir_entry*) buf;
919 for (i = 0; i <= root_dir_entries; i++) {
921 if (dir[i].attr == 0x00) {
927 if (dir[i].attr == 0xe5)
930 if (dir[i].attr == FAT_ATTR_VOLUME) {
931 dbg("found ATTR_VOLUME id in root dir");
935 dbg("skip dir entry");
938 if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
939 set_label_raw(id, label, 11);
940 set_label_string(id, label, 11);
941 } else if (strncmp(vs->type.fat.label, "NO NAME ", 11) != 0) {
942 set_label_raw(id, vs->type.fat.label, 11);
943 set_label_string(id, vs->type.fat.label, 11);
945 set_uuid(id, vs->type.fat.serno, UUID_DOS);
949 /* FAT32 root dir is a cluster chain like any other directory */
950 buf_size = vs->sectors_per_cluster * sector_size;
951 root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
952 dbg("root dir cluster %u", root_cluster);
953 start_data_sect = reserved + fat_size;
963 dbg("next cluster %u", next);
964 next_sect_off = (next - 2) * vs->sectors_per_cluster;
965 next_off = (start_data_sect + next_sect_off) * sector_size;
966 dbg("cluster offset 0x%llx", next_off);
969 buf = get_buffer(id, off + next_off, buf_size);
973 dir = (struct vfat_dir_entry*) buf;
974 count = buf_size / sizeof(struct vfat_dir_entry);
975 dbg("expected entries 0x%x", count);
977 for (i = 0; i <= count; i++) {
979 if (dir[i].attr == 0x00) {
985 if (dir[i].attr == 0xe5)
988 if (dir[i].attr == FAT_ATTR_VOLUME) {
989 dbg("found ATTR_VOLUME id in root dir");
994 dbg("skip dir entry");
998 fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
999 buf = get_buffer(id, off + fat_entry_off, buf_size);
1003 /* set next cluster */
1004 next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
1009 dbg("reached maximum follow count of root cluster chain, give up");
1012 if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
1013 set_label_raw(id, label, 11);
1014 set_label_string(id, label, 11);
1015 } else if (strncmp(vs->type.fat32.label, "NO NAME ", 11) == 0) {
1016 set_label_raw(id, vs->type.fat32.label, 11);
1017 set_label_string(id, vs->type.fat32.label, 11);
1019 set_uuid(id, vs->type.fat32.serno, UUID_DCE);
1022 id->usage_id = VOLUME_ID_FILESYSTEM;
1023 id->type_id = VOLUME_ID_VFAT;
1029 #define UDF_VSD_OFFSET 0x8000
1030 static int probe_udf(struct volume_id *id, __u64 off)
1032 struct volume_descriptor {
1033 struct descriptor_tag {
1042 } __attribute__((__packed__)) tag;
1044 struct anchor_descriptor {
1047 } __attribute__((__packed__)) anchor;
1048 struct primary_descriptor {
1054 } __attribute__((__packed__)) ident;
1055 } __attribute__((__packed__)) primary;
1056 } __attribute__((__packed__)) type;
1057 } __attribute__((__packed__)) *vd;
1059 struct volume_structure_descriptor {
1072 vsd = (struct volume_structure_descriptor *)
1073 get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
1077 if (strncmp(vsd->id, "NSR02", 5) == 0)
1079 if (strncmp(vsd->id, "NSR03", 5) == 0)
1081 if (strncmp(vsd->id, "BEA01", 5) == 0)
1083 if (strncmp(vsd->id, "BOOT2", 5) == 0)
1085 if (strncmp(vsd->id, "CD001", 5) == 0)
1087 if (strncmp(vsd->id, "CDW02", 5) == 0)
1089 if (strncmp(vsd->id, "TEA03", 5) == 0)
1094 /* search the next VSD to get the logical block size of the volume */
1095 for (bs = 0x800; bs < 0x8000; bs += 0x800) {
1096 vsd = (struct volume_structure_descriptor *)
1097 get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
1100 dbg("test for blocksize: 0x%x", bs);
1101 if (vsd->id[0] != '\0')
1107 /* search the list of VSDs for a NSR descriptor */
1108 for (b = 0; b < 64; b++) {
1109 vsd = (struct volume_structure_descriptor *)
1110 get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
1114 dbg("vsd: %c%c%c%c%c",
1115 vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
1117 if (vsd->id[0] == '\0')
1119 if (strncmp(vsd->id, "NSR02", 5) == 0)
1121 if (strncmp(vsd->id, "NSR03", 5) == 0)
1127 /* read anchor volume descriptor */
1128 vd = (struct volume_descriptor *)
1129 get_buffer(id, off + (256 * bs), 0x200);
1133 type = le16_to_cpu(vd->tag.id);
1134 if (type != 2) /* TAG_ID_AVDP */
1137 /* get desriptor list address and block count */
1138 count = le32_to_cpu(vd->type.anchor.length) / bs;
1139 loc = le32_to_cpu(vd->type.anchor.location);
1140 dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
1142 /* pick the primary descriptor from the list */
1143 for (b = 0; b < count; b++) {
1144 vd = (struct volume_descriptor *)
1145 get_buffer(id, off + ((loc + b) * bs), 0x200);
1149 type = le16_to_cpu(vd->tag.id);
1150 dbg("descriptor type %i", type);
1152 /* check validity */
1155 if (le32_to_cpu(vd->tag.location) != loc + b)
1158 if (type == 1) /* TAG_ID_PVD */
1164 set_label_raw(id, &(vd->type.primary.ident.clen), 32);
1166 clen = vd->type.primary.ident.clen;
1167 dbg("label string charsize=%i bit", clen);
1169 set_label_string(id, vd->type.primary.ident.c, 31);
1170 else if (clen == 16)
1171 set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
1174 id->usage_id = VOLUME_ID_FILESYSTEM;
1175 id->type_id = VOLUME_ID_UDF;
1181 #define ISO_SUPERBLOCK_OFFSET 0x8000
1182 static int probe_iso9660(struct volume_id *id, __u64 off)
1184 union iso_super_block {
1192 } __attribute__((__packed__)) iso;
1198 } __attribute__((__packed__)) hs;
1199 } __attribute__((__packed__)) *is;
1201 is = (union iso_super_block *)
1202 get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
1206 if (strncmp(is->iso.id, "CD001", 5) == 0) {
1207 set_label_raw(id, is->iso.volume_id, 32);
1208 set_label_string(id, is->iso.volume_id, 32);
1211 if (strncmp(is->hs.id, "CDROM", 5) == 0)
1216 id->usage_id = VOLUME_ID_FILESYSTEM;
1217 id->type_id = VOLUME_ID_ISO9660;
1218 id->type = "iso9660";
1223 #define UFS_MAGIC 0x00011954
1224 #define UFS2_MAGIC 0x19540119
1225 #define UFS_MAGIC_FEA 0x00195612
1226 #define UFS_MAGIC_LFN 0x00095014
1229 static int probe_ufs(struct volume_id *id, __u64 off)
1231 struct ufs_super_block {
1265 __u32 fs_npsect_state;
1266 __u32 fs_interleave;
1284 } __attribute__((__packed__)) fs_cstotal;
1294 __u32 fs_maxcluster;
1296 __u16 fs_opostbl[16][8];
1297 } __attribute__((__packed__)) fs_u1;
1300 __u8 fs_volname[32];
1305 __u32 fs_contigdirs;
1307 __u32 fs_maxcluster;
1311 __s64 fs_sparecon64[17];
1313 struct ufs2_csum_total {
1318 __u64 cs_numclusters;
1320 } __attribute__((__packed__)) fs_cstotal;
1321 struct ufs_timeval {
1324 } __attribute__((__packed__)) fs_time;
1328 __s64 fs_pendingblocks;
1329 __s32 fs_pendinginodes;
1330 } __attribute__((__packed__)) fs_u2;
1334 __s32 fs_sparecon[53];
1336 __s32 fs_sparecon2[1];
1340 } __attribute__((__packed__)) fs_sun;
1342 __s32 fs_sparecon[53];
1344 __s32 fs_sparecon2[1];
1348 } __attribute__((__packed__)) fs_sunx86;
1350 __s32 fs_sparecon[50];
1351 __s32 fs_contigsumsize;
1352 __s32 fs_maxsymlinklen;
1354 __u32 fs_maxfilesize[2];
1358 } __attribute__((__packed__)) fs_44;
1360 __s32 fs_postblformat;
1366 } __attribute__((__packed__)) *ufs;
1370 int offsets[] = {0, 8, 64, 256, -1};
1372 for (i = 0; offsets[i] >= 0; i++) {
1373 ufs = (struct ufs_super_block *)
1374 get_buffer(id, off + (offsets[i] * 0x400), 0x800);
1378 dbg("offset 0x%x", offsets[i] * 0x400);
1379 magic = be32_to_cpu(ufs->fs_magic);
1380 if ((magic == UFS_MAGIC) ||
1381 (magic == UFS2_MAGIC) ||
1382 (magic == UFS_MAGIC_FEA) ||
1383 (magic == UFS_MAGIC_LFN)) {
1384 dbg("magic 0x%08x(be)", magic);
1387 magic = le32_to_cpu(ufs->fs_magic);
1388 if ((magic == UFS_MAGIC) ||
1389 (magic == UFS2_MAGIC) ||
1390 (magic == UFS_MAGIC_FEA) ||
1391 (magic == UFS_MAGIC_LFN)) {
1392 dbg("magic 0x%08x(le)", magic);
1399 id->usage_id = VOLUME_ID_FILESYSTEM;
1400 id->type_id = VOLUME_ID_UFS;
1406 static int probe_mac_partition_map(struct volume_id *id, __u64 off)
1408 struct mac_driver_desc {
1412 } __attribute__((__packed__)) *driver;
1414 struct mac_partition {
1422 } __attribute__((__packed__)) *part;
1426 buf = get_buffer(id, off, 0x200);
1430 part = (struct mac_partition *) buf;
1431 if ((strncmp(part->signature, "PM", 2) == 0) &&
1432 (strncmp(part->type, "Apple_partition_map", 19) == 0)) {
1433 /* linux creates an own subdevice for the map
1434 * just return the type if the drive header is missing */
1435 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1436 id->type_id = VOLUME_ID_MACPARTMAP;
1437 id->type = "mac_partition_map";
1441 driver = (struct mac_driver_desc *) buf;
1442 if (strncmp(driver->signature, "ER", 2) == 0) {
1443 /* we are on a main device, like a CD
1444 * just try to probe the first partition from the map */
1445 unsigned int bsize = be16_to_cpu(driver->block_size);
1449 /* get first entry of partition table */
1450 buf = get_buffer(id, off + bsize, 0x200);
1454 part = (struct mac_partition *) buf;
1455 if (strncmp(part->signature, "PM", 2) != 0)
1458 part_count = be32_to_cpu(part->map_count);
1459 dbg("expecting %d partition entries", part_count);
1461 if (id->partitions != NULL)
1462 free(id->partitions);
1464 malloc(part_count * sizeof(struct volume_id_partition));
1465 if (id->partitions == NULL)
1467 memset(id->partitions, 0x00, sizeof(struct volume_id_partition));
1469 id->partition_count = part_count;
1471 for (i = 0; i < part_count; i++) {
1475 buf = get_buffer(id, off + ((i+1) * bsize), 0x200);
1479 part = (struct mac_partition *) buf;
1480 if (strncmp(part->signature, "PM", 2) != 0)
1483 poff = be32_to_cpu(part->start_block) * bsize;
1484 plen = be32_to_cpu(part->block_count) * bsize;
1485 dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
1486 part->type, poff, plen);
1488 id->partitions[i].off = poff;
1489 id->partitions[i].len = plen;
1491 if (strncmp(part->type, "Apple_Free", 10) == 0) {
1492 id->partitions[i].usage_id = VOLUME_ID_UNUSED;
1493 } else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
1494 id->partitions[i].usage_id = VOLUME_ID_PARTITIONTABLE;
1495 id->partitions[i].type_id = VOLUME_ID_MACPARTMAP;
1497 id->partitions[i].usage_id = VOLUME_ID_UNPROBED;
1500 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1501 id->type_id = VOLUME_ID_MACPARTMAP;
1502 id->type = "mac_partition_map";
1509 #define HFS_SUPERBLOCK_OFFSET 0x400
1510 #define HFS_NODE_LEAF 0xff
1511 #define HFSPLUS_POR_CNID 1
1512 #define HFSPLUS_EXTENT_COUNT 8
1513 static int probe_hfs_hfsplus(struct volume_id *id, __u64 off)
1515 struct hfs_finder_info{
1523 } __attribute__((__packed__));
1544 __u32 xt_clump_size;
1545 __u32 ct_clump_size;
1546 __u16 num_root_dirs;
1549 struct hfs_finder_info finder_info;
1551 __u16 embed_startblock;
1552 __u16 embed_blockcount;
1553 } __attribute__((__packed__)) *hfs;
1555 struct hfsplus_bnode_descriptor {
1562 } __attribute__((__packed__));
1564 struct hfsplus_bheader_record {
1571 } __attribute__((__packed__));
1573 struct hfsplus_catalog_key {
1577 __u8 unicode[255 * 2];
1578 } __attribute__((__packed__));
1580 struct hfsplus_extent {
1583 } __attribute__((__packed__));
1585 struct hfsplus_fork {
1589 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1590 } __attribute__((__packed__));
1592 struct hfsplus_vol_header {
1596 __u32 last_mount_vers;
1608 __u32 rsrc_clump_sz;
1609 __u32 data_clump_sz;
1612 __u64 encodings_bmp;
1613 struct hfs_finder_info finder_info;
1614 struct hfsplus_fork alloc_file;
1615 struct hfsplus_fork ext_file;
1616 struct hfsplus_fork cat_file;
1617 struct hfsplus_fork attr_file;
1618 struct hfsplus_fork start_file;
1619 } __attribute__((__packed__)) *hfsplus;
1621 unsigned int blocksize;
1622 unsigned int cat_block;
1623 unsigned int ext_block_start;
1624 unsigned int ext_block_count;
1626 unsigned int leaf_node_head;
1627 unsigned int leaf_node_count;
1628 unsigned int leaf_node_size;
1629 unsigned int leaf_block;
1631 unsigned int alloc_block_size;
1632 unsigned int alloc_first_block;
1633 unsigned int embed_first_block;
1634 unsigned int record_count;
1635 struct hfsplus_bnode_descriptor *descr;
1636 struct hfsplus_bheader_record *bnode;
1637 struct hfsplus_catalog_key *key;
1638 unsigned int label_len;
1639 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1642 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1646 hfs = (struct hfs_mdb *) buf;
1647 if (strncmp(hfs->signature, "BD", 2) != 0)
1650 /* it may be just a hfs wrapper for hfs+ */
1651 if (strncmp(hfs->embed_sig, "H+", 2) == 0) {
1652 alloc_block_size = be32_to_cpu(hfs->al_blk_size);
1653 dbg("alloc_block_size 0x%x", alloc_block_size);
1655 alloc_first_block = be16_to_cpu(hfs->al_bl_st);
1656 dbg("alloc_first_block 0x%x", alloc_first_block);
1658 embed_first_block = be16_to_cpu(hfs->embed_startblock);
1659 dbg("embed_first_block 0x%x", embed_first_block);
1661 off += (alloc_first_block * 512) +
1662 (embed_first_block * alloc_block_size);
1663 dbg("hfs wrapped hfs+ found at offset 0x%llx", off);
1665 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1671 if (hfs->label_len > 0 && hfs->label_len < 28) {
1672 set_label_raw(id, hfs->label, hfs->label_len);
1673 set_label_string(id, hfs->label, hfs->label_len) ;
1676 set_uuid(id, hfs->finder_info.id, UUID_HFS);
1678 id->usage_id = VOLUME_ID_FILESYSTEM;
1679 id->type_id = VOLUME_ID_HFS;
1685 hfsplus = (struct hfsplus_vol_header *) buf;
1686 if (strncmp(hfsplus->signature, "H+", 2) == 0)
1688 if (strncmp(hfsplus->signature, "HX", 2) == 0)
1693 set_uuid(id, hfsplus->finder_info.id, UUID_HFS);
1695 blocksize = be32_to_cpu(hfsplus->blocksize);
1696 dbg("blocksize %u", blocksize);
1698 memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
1699 cat_block = be32_to_cpu(extents[0].start_block);
1700 dbg("catalog start block 0x%x", cat_block);
1702 buf = get_buffer(id, off + (cat_block * blocksize), 0x2000);
1706 bnode = (struct hfsplus_bheader_record *)
1707 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1709 leaf_node_head = be32_to_cpu(bnode->leaf_head);
1710 dbg("catalog leaf node 0x%x", leaf_node_head);
1712 leaf_node_size = be16_to_cpu(bnode->node_size);
1713 dbg("leaf node size 0x%x", leaf_node_size);
1715 leaf_node_count = be32_to_cpu(bnode->leaf_count);
1716 dbg("leaf node count 0x%x", leaf_node_count);
1717 if (leaf_node_count == 0)
1720 leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
1722 /* get physical location */
1723 for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
1724 ext_block_start = be32_to_cpu(extents[ext].start_block);
1725 ext_block_count = be32_to_cpu(extents[ext].block_count);
1726 dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
1728 if (ext_block_count == 0)
1731 /* this is our extent */
1732 if (leaf_block < ext_block_count)
1735 leaf_block -= ext_block_count;
1737 if (ext == HFSPLUS_EXTENT_COUNT)
1739 dbg("found block in extent %i", ext);
1741 leaf_off = (ext_block_start + leaf_block) * blocksize;
1743 buf = get_buffer(id, off + leaf_off, leaf_node_size);
1747 descr = (struct hfsplus_bnode_descriptor *) buf;
1748 dbg("descriptor type 0x%x", descr->type);
1750 record_count = be16_to_cpu(descr->num_recs);
1751 dbg("number of records %u", record_count);
1752 if (record_count == 0)
1755 if (descr->type != HFS_NODE_LEAF)
1758 key = (struct hfsplus_catalog_key *)
1759 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1761 dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
1762 if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
1765 label_len = be16_to_cpu(key->unicode_len) * 2;
1766 dbg("label unicode16 len %i", label_len);
1767 set_label_raw(id, key->unicode, label_len);
1768 set_label_unicode16(id, key->unicode, BE, label_len);
1771 id->usage_id = VOLUME_ID_FILESYSTEM;
1772 id->type_id = VOLUME_ID_HFSPLUS;
1773 id->type = "hfsplus";
1778 #define MFT_RECORD_VOLUME 3
1779 #define MFT_RECORD_ATTR_VOLUME_NAME 0x60
1780 #define MFT_RECORD_ATTR_VOLUME_INFO 0x70
1781 #define MFT_RECORD_ATTR_OBJECT_ID 0x40
1782 #define MFT_RECORD_ATTR_END 0xffffffffu
1783 static int probe_ntfs(struct volume_id *id, __u64 off)
1785 struct ntfs_super_block {
1788 __u16 bytes_per_sector;
1789 __u8 sectors_per_cluster;
1790 __u16 reserved_sectors;
1795 __u16 sectors_per_fat;
1796 __u16 sectors_per_track;
1798 __u32 hidden_sectors;
1799 __u32 large_sectors;
1801 __u64 number_of_sectors;
1802 __u64 mft_cluster_location;
1803 __u64 mft_mirror_cluster_location;
1804 __s8 cluster_per_mft_record;
1806 __s8 cluster_per_index_record;
1808 __u8 volume_serial[8];
1810 } __attribute__((__packed__)) *ns;
1812 struct master_file_table_record {
1817 __u16 sequence_number;
1822 __u32 bytes_allocated;
1823 } __attribute__((__packed__)) *mftr;
1825 struct file_attribute {
1835 } __attribute__((__packed__)) *attr;
1837 struct volume_info {
1841 } __attribute__((__packed__)) *info;
1843 unsigned int sector_size;
1844 unsigned int cluster_size;
1847 unsigned int mft_record_size;
1848 unsigned int attr_type;
1849 unsigned int attr_off;
1850 unsigned int attr_len;
1851 unsigned int val_off;
1852 unsigned int val_len;
1856 ns = (struct ntfs_super_block *) get_buffer(id, off, 0x200);
1860 if (strncmp(ns->oem_id, "NTFS", 4) != 0)
1863 set_uuid(id, ns->volume_serial, UUID_NTFS);
1865 sector_size = le16_to_cpu(ns->bytes_per_sector);
1866 cluster_size = ns->sectors_per_cluster * sector_size;
1867 mft_cluster = le64_to_cpu(ns->mft_cluster_location);
1868 mft_off = mft_cluster * cluster_size;
1870 if (ns->cluster_per_mft_record < 0)
1871 /* size = -log2(mft_record_size); normally 1024 Bytes */
1872 mft_record_size = 1 << -ns->cluster_per_mft_record;
1874 mft_record_size = ns->cluster_per_mft_record * cluster_size;
1876 dbg("sectorsize 0x%x", sector_size);
1877 dbg("clustersize 0x%x", cluster_size);
1878 dbg("mftcluster %lli", mft_cluster);
1879 dbg("mftoffset 0x%llx", mft_off);
1880 dbg("cluster per mft_record %i", ns->cluster_per_mft_record);
1881 dbg("mft record size %i", mft_record_size);
1883 buf = get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
1888 mftr = (struct master_file_table_record*) buf;
1890 dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
1891 if (strncmp(mftr->magic, "FILE", 4) != 0)
1894 attr_off = le16_to_cpu(mftr->attrs_offset);
1895 dbg("file $Volume's attributes are at offset %i", attr_off);
1898 attr = (struct file_attribute*) &buf[attr_off];
1899 attr_type = le32_to_cpu(attr->type);
1900 attr_len = le16_to_cpu(attr->len);
1901 val_off = le16_to_cpu(attr->value_offset);
1902 val_len = le32_to_cpu(attr->value_len);
1903 attr_off += attr_len;
1908 if (attr_off >= mft_record_size)
1911 if (attr_type == MFT_RECORD_ATTR_END)
1914 dbg("found attribute type 0x%x, len %i, at offset %i",
1915 attr_type, attr_len, attr_off);
1917 if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
1918 dbg("found info, len %i", val_len);
1919 info = (struct volume_info*) (((__u8 *) attr) + val_off);
1920 snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1,
1921 "%u.%u", info->major_ver, info->minor_ver);
1924 if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
1925 dbg("found label, len %i", val_len);
1926 if (val_len > VOLUME_ID_LABEL_SIZE)
1927 val_len = VOLUME_ID_LABEL_SIZE;
1929 val = ((__u8 *) attr) + val_off;
1930 set_label_raw(id, val, val_len);
1931 set_label_unicode16(id, val, LE, val_len);
1936 id->usage_id = VOLUME_ID_FILESYSTEM;
1937 id->type_id = VOLUME_ID_NTFS;
1943 #define LARGEST_PAGESIZE 0x4000
1944 static int probe_swap(struct volume_id *id, __u64 off)
1949 /* huhh, the swap signature is on the end of the PAGE_SIZE */
1950 for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
1951 sig = get_buffer(id, off + page-10, 10);
1955 if (strncmp(sig, "SWAP-SPACE", 10) == 0) {
1956 strcpy(id->type_version, "1");
1959 if (strncmp(sig, "SWAPSPACE2", 10) == 0) {
1960 strcpy(id->type_version, "2");
1967 id->usage_id = VOLUME_ID_OTHER;
1968 id->type_id = VOLUME_ID_SWAP;
1974 /* probe volume for filesystem type and try to read label+uuid */
1975 int volume_id_probe(struct volume_id *id,
1976 enum volume_id_type type,
1977 unsigned long long off,
1978 unsigned long long size)
1986 case VOLUME_ID_MSDOSPARTTABLE:
1987 rc = probe_msdos_part_table(id, off);
1989 case VOLUME_ID_EXT3:
1990 case VOLUME_ID_EXT2:
1991 rc = probe_ext(id, off);
1993 case VOLUME_ID_REISERFS:
1994 rc = probe_reiserfs(id, off);
1997 rc = probe_xfs(id, off);
2000 rc = probe_jfs(id, off);
2002 case VOLUME_ID_VFAT:
2003 rc = probe_vfat(id, off);
2006 rc = probe_udf(id, off);
2008 case VOLUME_ID_ISO9660:
2009 rc = probe_iso9660(id, off);
2011 case VOLUME_ID_MACPARTMAP:
2012 rc = probe_mac_partition_map(id, off);
2015 case VOLUME_ID_HFSPLUS:
2016 rc = probe_hfs_hfsplus(id, off);
2019 rc = probe_ufs(id, off);
2021 case VOLUME_ID_NTFS:
2022 rc = probe_ntfs(id, off);
2024 case VOLUME_ID_SWAP:
2025 rc = probe_swap(id, off);
2027 case VOLUME_ID_LINUX_RAID:
2028 rc = probe_linux_raid(id, off, size);
2030 case VOLUME_ID_LVM1:
2031 rc = probe_lvm1(id, off);
2033 case VOLUME_ID_LVM2:
2034 rc = probe_lvm2(id, off);
2038 rc = probe_linux_raid(id, off, size);
2042 /* signature in the first block */
2043 rc = probe_ntfs(id, off);
2046 rc = probe_vfat(id, off);
2049 rc = probe_msdos_part_table(id, off);
2052 rc = probe_mac_partition_map(id, off);
2055 rc = probe_xfs(id, off);
2059 /* fill buffer with maximum */
2060 get_buffer(id, 0, SB_BUFFER_SIZE);
2062 rc = probe_swap(id, off);
2065 rc = probe_ext(id, off);
2068 rc = probe_reiserfs(id, off);
2071 rc = probe_jfs(id, off);
2074 rc = probe_udf(id, off);
2077 rc = probe_iso9660(id, off);
2080 rc = probe_hfs_hfsplus(id, off);
2083 rc = probe_ufs(id, off);
2086 rc = probe_lvm1(id, off);
2089 rc = probe_lvm2(id, off);
2096 /* If the filestystem in recognized, we free the allocated buffers,
2097 otherwise they will stay in place for the possible next probe call */
2104 /* open volume by already open file descriptor */
2105 struct volume_id *volume_id_open_fd(int fd)
2107 struct volume_id *id;
2109 id = malloc(sizeof(struct volume_id));
2112 memset(id, 0x00, sizeof(struct volume_id));
2119 /* open volume by device node */
2120 struct volume_id *volume_id_open_node(const char *path)
2122 struct volume_id *id;
2125 fd = open(path, O_RDONLY | O_NONBLOCK);
2127 dbg("unable to open '%s'", path);
2131 id = volume_id_open_fd(fd);
2135 /* close fd on device close */
2141 /* open volume by major/minor */
2142 struct volume_id *volume_id_open_dev_t(dev_t devt)
2144 struct volume_id *id;
2145 __u8 tmp_node[VOLUME_ID_PATH_MAX];
2147 snprintf(tmp_node, VOLUME_ID_PATH_MAX,
2148 "/tmp/volume-%u-%u-%u", getpid(), major(devt), minor(devt));
2149 tmp_node[VOLUME_ID_PATH_MAX] = '\0';
2151 /* create tempory node to open the block device */
2153 if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0)
2156 id = volume_id_open_node(tmp_node);
2163 /* free allocated volume info */
2164 void volume_id_close(struct volume_id *id)
2169 if (id->fd_close != 0)
2174 if (id->partitions != NULL)
2175 free(id->partitions);