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 HPT37X_CONFIG_OFF 0x1200
267 #define HPT37X_MAGIC_OK 0x5a7816f0
268 #define HPT37X_MAGIC_BAD 0x5a7816fd
269 static int probe_highpoint_ataraid(struct volume_id *id, __u64 off)
276 } __attribute__((packed)) *hpt;
280 buf = get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200);
284 hpt = (struct hpt37x *) buf;
286 if (hpt->magic != HPT37X_MAGIC_OK && hpt->magic != HPT37X_MAGIC_BAD)
289 id->usage_id = VOLUME_ID_RAID;
290 id->type_id = VOLUME_ID_HPTRAID;
291 id->type = "hpt_ataraid_member";
296 #define LVM1_SB_OFF 0x400
297 #define LVM1_MAGIC "HM"
298 static int probe_lvm1(struct volume_id *id, __u64 off)
300 struct lvm2_super_block {
302 } __attribute__((packed)) *lvm;
306 buf = get_buffer(id, off + LVM1_SB_OFF, 0x800);
310 lvm = (struct lvm2_super_block *) buf;
312 if (strncmp(lvm->id, LVM1_MAGIC, 2) != 0)
315 id->usage_id = VOLUME_ID_RAID;
316 id->type_id = VOLUME_ID_LVM1;
317 id->type = "LVM1_member";
322 #define LVM2_LABEL_ID "LABELONE"
323 #define LVM2LABEL_SCAN_SECTORS 4
324 static int probe_lvm2(struct volume_id *id, __u64 off)
326 struct lvm2_super_block {
332 } __attribute__((packed)) *lvm;
337 buf = get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
342 for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
343 lvm = (struct lvm2_super_block *) &buf[soff];
345 if (strncmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
352 strncpy(id->type_version, lvm->type, 8);
353 id->usage_id = VOLUME_ID_RAID;
354 id->type_id = VOLUME_ID_LVM2;
355 id->type = "LVM2_member";
360 #define MD_RESERVED_BYTES 0x10000
361 #define MD_MAGIC 0xa92b4efc
362 static int probe_linux_raid(struct volume_id *id, __u64 off, __u64 size)
364 struct mdp_super_block {
377 __u32 not_persistent;
381 } __attribute__((packed)) *mdp;
390 sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
391 buf = get_buffer(id, off + sboff, 0x800);
395 mdp = (struct mdp_super_block *) buf;
397 if (le32_to_cpu(mdp->md_magic) != MD_MAGIC)
400 memcpy(uuid, &mdp->set_uuid0, 4);
401 memcpy(&uuid[4], &mdp->set_uuid1, 12);
402 set_uuid(id, uuid, UUID_DCE);
404 snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1, "%u.%u.%u",
405 le32_to_cpu(mdp->major_version),
406 le32_to_cpu(mdp->minor_version),
407 le32_to_cpu(mdp->patch_version));
409 dbg("found raid signature");
410 id->usage_id = VOLUME_ID_RAID;
411 id->type = "linux_raid_member";
416 #define MSDOS_MAGIC "\x55\xaa"
417 #define MSDOS_PARTTABLE_OFFSET 0x1be
418 #define MSDOS_SIG_OFF 0x1fe
420 #define DOS_EXTENDED_PARTITION 0x05
421 #define LINUX_EXTENDED_PARTITION 0x85
422 #define WIN98_EXTENDED_PARTITION 0x0f
423 #define LINUX_RAID_PARTITION 0xfd
424 #define is_extended(type) \
425 (type == DOS_EXTENDED_PARTITION || \
426 type == WIN98_EXTENDED_PARTITION || \
427 type == LINUX_EXTENDED_PARTITION)
428 #define is_raid(type) \
429 (type == LINUX_RAID_PARTITION)
430 static int probe_msdos_part_table(struct volume_id *id, __u64 off)
432 struct msdos_partition_entry {
443 } __attribute__((packed)) *part;
454 struct volume_id_partition *p;
456 buf = get_buffer(id, off, 0x200);
460 if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
463 /* check flags on all entries for a valid partition table */
464 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
465 for (i = 0; i < 4; i++) {
466 if (part[i].boot_ind != 0 &&
467 part[i].boot_ind != 0x80)
470 if (le32_to_cpu(part[i].nr_sects) != 0)
476 if (id->partitions != NULL)
477 free(id->partitions);
478 id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX *
479 sizeof(struct volume_id_partition));
480 if (id->partitions == NULL)
482 memset(id->partitions, 0x00,
483 VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition));
485 for (i = 0; i < 4; i++) {
486 poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
487 plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
492 p = &id->partitions[i];
494 p->partition_type_raw = part[i].sys_ind;
496 if (is_extended(part[i].sys_ind)) {
497 dbg("found extended partition at 0x%llx", poff);
498 p->usage_id = VOLUME_ID_PARTITIONTABLE;
499 p->type_id = VOLUME_ID_MSDOSEXTENDED;
500 p->type = "msdos_extended_partition";
502 extended = off + poff;
504 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
505 part[i].sys_ind, poff, plen);
507 if (is_raid(part[i].sys_ind))
508 p->usage_id = VOLUME_ID_RAID;
510 p->usage_id = VOLUME_ID_UNPROBED;
515 id->partition_count = i+1;
522 /* follow extended partition chain and add data partitions */
525 dbg("extended chain limit reached");
529 buf = get_buffer(id, current, 0x200);
533 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
535 if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
540 for (i = 0; i < 4; i++) {
541 poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
542 plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
547 if (is_extended(part[i].sys_ind)) {
548 dbg("found extended partition at 0x%llx", poff);
550 next = extended + poff;
552 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
553 part[i].sys_ind, poff, plen);
555 /* we always start at the 5th entry */
556 while (id->partition_count < 4)
557 id->partitions[id->partition_count++].usage_id =
560 p = &id->partitions[id->partition_count];
562 if (is_raid(part[i].sys_ind))
563 p->usage_id = VOLUME_ID_RAID;
565 p->usage_id = VOLUME_ID_UNPROBED;
567 p->off = current + poff;
569 id->partition_count++;
571 p->partition_type_raw = part[i].sys_ind;
573 if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
574 dbg("to many partitions");
583 id->usage_id = VOLUME_ID_PARTITIONTABLE;
584 id->type_id = VOLUME_ID_MSDOSPARTTABLE;
585 id->type = "msdos_partition_table";
590 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
591 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
592 #define EXT_SUPERBLOCK_OFFSET 0x400
593 static int probe_ext(struct volume_id *id, __u64 off)
595 struct ext2_super_block {
598 __u32 r_blocks_count;
599 __u32 free_blocks_count;
600 __u32 free_inodes_count;
601 __u32 first_data_block;
602 __u32 log_block_size;
607 __u32 feature_compat;
608 __u32 feature_incompat;
609 __u32 feature_ro_compat;
611 __u8 volume_name[16];
612 } __attribute__((__packed__)) *es;
614 es = (struct ext2_super_block *)
615 get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
619 if (es->magic[0] != 0123 ||
620 es->magic[1] != 0357)
623 set_label_raw(id, es->volume_name, 16);
624 set_label_string(id, es->volume_name, 16);
625 set_uuid(id, es->uuid, UUID_DCE);
627 if ((le32_to_cpu(es->feature_compat) &
628 EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
629 id->usage_id = VOLUME_ID_FILESYSTEM;
630 id->type_id = VOLUME_ID_EXT3;
633 id->usage_id = VOLUME_ID_FILESYSTEM;
634 id->type_id = VOLUME_ID_EXT2;
641 #define REISERFS1_SUPERBLOCK_OFFSET 0x2000
642 #define REISERFS_SUPERBLOCK_OFFSET 0x10000
643 static int probe_reiserfs(struct volume_id *id, __u64 off)
645 struct reiserfs_super_block {
651 __u32 orig_journal_size;
659 } __attribute__((__packed__)) *rs;
661 rs = (struct reiserfs_super_block *)
662 get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
666 if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0) {
667 strcpy(id->type_version, "3.6");
671 if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0) {
672 strcpy(id->type_version, "JR");
676 rs = (struct reiserfs_super_block *)
677 get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
681 if (strncmp(rs->magic, "ReIsErFs", 8) == 0) {
682 strcpy(id->type_version, "3.5");
689 set_label_raw(id, rs->label, 16);
690 set_label_string(id, rs->label, 16);
691 set_uuid(id, rs->uuid, UUID_DCE);
693 id->usage_id = VOLUME_ID_FILESYSTEM;
694 id->type_id = VOLUME_ID_REISERFS;
695 id->type = "reiserfs";
700 static int probe_xfs(struct volume_id *id, __u64 off)
702 struct xfs_super_block {
715 } __attribute__((__packed__)) *xs;
717 xs = (struct xfs_super_block *) get_buffer(id, off, 0x200);
721 if (strncmp(xs->magic, "XFSB", 4) != 0)
724 set_label_raw(id, xs->fname, 12);
725 set_label_string(id, xs->fname, 12);
726 set_uuid(id, xs->uuid, UUID_DCE);
728 id->usage_id = VOLUME_ID_FILESYSTEM;
729 id->type_id = VOLUME_ID_XFS;
735 #define JFS_SUPERBLOCK_OFFSET 0x8000
736 static int probe_jfs(struct volume_id *id, __u64 off)
738 struct jfs_super_block {
749 } __attribute__((__packed__)) *js;
751 js = (struct jfs_super_block *)
752 get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
756 if (strncmp(js->magic, "JFS1", 4) != 0)
759 set_label_raw(id, js->label, 16);
760 set_label_string(id, js->label, 16);
761 set_uuid(id, js->uuid, UUID_DCE);
763 id->usage_id = VOLUME_ID_FILESYSTEM;
764 id->type_id = VOLUME_ID_JFS;
770 #define FAT12_MAX 0xff5
771 #define FAT16_MAX 0xfff5
772 #define FAT_ATTR_VOLUME 0x08
773 static int probe_vfat(struct volume_id *id, __u64 off)
775 struct vfat_super_block {
779 __u8 sectors_per_cluster;
791 struct fat_super_block {
798 } __attribute__((__packed__)) fat;
799 struct fat32_super_block {
813 } __attribute__((__packed__)) fat32;
814 } __attribute__((__packed__)) type;
815 } __attribute__((__packed__)) *vs;
817 struct vfat_dir_entry {
829 } __attribute__((__packed__)) *dir;
841 __u32 start_data_sect;
842 __u16 root_dir_entries;
850 vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
854 /* believe only that's fat, don't trust the version
855 * the cluster_count will tell us
857 if (strncmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
860 if (strncmp(vs->type.fat32.magic, "FAT32 ", 8) == 0)
863 if (strncmp(vs->type.fat.magic, "FAT16 ", 8) == 0)
866 if (strncmp(vs->type.fat.magic, "MSDOS", 5) == 0)
869 if (strncmp(vs->type.fat.magic, "FAT12 ", 8) == 0)
873 * There are old floppies out there without a magic, so we check
874 * for well known values and guess if it's a fat volume
877 /* boot jump address check */
878 if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
879 vs->boot_jump[0] != 0xe9)
886 /* cluster size check*/
887 if (vs->sectors_per_cluster == 0 ||
888 (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
892 if (vs->media < 0xf8 && vs->media != 0xf0)
900 /* sector size check */
901 sector_size = le16_to_cpu(vs->sector_size);
902 if (sector_size != 0x200 && sector_size != 0x400 &&
903 sector_size != 0x800 && sector_size != 0x1000)
906 dbg("sector_size 0x%x", sector_size);
907 dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
909 dir_entries = le16_to_cpu(vs->dir_entries);
910 reserved = le16_to_cpu(vs->reserved);
911 dbg("reserved 0x%x", reserved);
913 sect_count = le16_to_cpu(vs->sectors);
915 sect_count = le32_to_cpu(vs->total_sect);
916 dbg("sect_count 0x%x", sect_count);
918 fat_length = le16_to_cpu(vs->fat_length);
920 fat_length = le32_to_cpu(vs->type.fat32.fat32_length);
921 dbg("fat_length 0x%x", fat_length);
923 fat_size = fat_length * vs->fats;
924 dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
925 (sector_size-1)) / sector_size;
926 dbg("dir_size 0x%x", dir_size);
928 cluster_count = sect_count - (reserved + fat_size + dir_size);
929 cluster_count /= vs->sectors_per_cluster;
930 dbg("cluster_count 0x%x", cluster_count);
932 if (cluster_count < FAT12_MAX) {
933 strcpy(id->type_version, "FAT12");
934 } else if (cluster_count < FAT16_MAX) {
935 strcpy(id->type_version, "FAT16");
937 strcpy(id->type_version, "FAT32");
941 /* the label may be an attribute in the root directory */
942 root_start = (reserved + fat_size) * sector_size;
943 dbg("root dir start 0x%llx", root_start);
944 root_dir_entries = le16_to_cpu(vs->dir_entries);
945 dbg("expected entries 0x%x", root_dir_entries);
947 buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
948 buf = get_buffer(id, off + root_start, buf_size);
952 dir = (struct vfat_dir_entry*) buf;
954 for (i = 0; i <= root_dir_entries; i++) {
956 if (dir[i].name[0] == 0x00) {
962 if (dir[i].name[0] == 0xe5)
965 if (dir[i].attr == FAT_ATTR_VOLUME) {
966 dbg("found ATTR_VOLUME id in root dir");
970 dbg("skip dir entry");
973 if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
974 set_label_raw(id, label, 11);
975 set_label_string(id, label, 11);
976 } else if (strncmp(vs->type.fat.label, "NO NAME ", 11) != 0) {
977 set_label_raw(id, vs->type.fat.label, 11);
978 set_label_string(id, vs->type.fat.label, 11);
980 set_uuid(id, vs->type.fat.serno, UUID_DOS);
984 /* FAT32 root dir is a cluster chain like any other directory */
985 buf_size = vs->sectors_per_cluster * sector_size;
986 root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
987 dbg("root dir cluster %u", root_cluster);
988 start_data_sect = reserved + fat_size;
998 dbg("next cluster %u", next);
999 next_sect_off = (next - 2) * vs->sectors_per_cluster;
1000 next_off = (start_data_sect + next_sect_off) * sector_size;
1001 dbg("cluster offset 0x%llx", next_off);
1004 buf = get_buffer(id, off + next_off, buf_size);
1008 dir = (struct vfat_dir_entry*) buf;
1009 count = buf_size / sizeof(struct vfat_dir_entry);
1010 dbg("expected entries 0x%x", count);
1012 for (i = 0; i <= count; i++) {
1014 if (dir[i].name[0] == 0x00) {
1020 if (dir[i].name[0] == 0xe5)
1023 if (dir[i].attr == FAT_ATTR_VOLUME) {
1024 dbg("found ATTR_VOLUME id in root dir");
1025 label = dir[i].name;
1029 dbg("skip dir entry");
1033 fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
1034 buf = get_buffer(id, off + fat_entry_off, buf_size);
1038 /* set next cluster */
1039 next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
1044 dbg("reached maximum follow count of root cluster chain, give up");
1047 if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
1048 set_label_raw(id, label, 11);
1049 set_label_string(id, label, 11);
1050 } else if (strncmp(vs->type.fat32.label, "NO NAME ", 11) == 0) {
1051 set_label_raw(id, vs->type.fat32.label, 11);
1052 set_label_string(id, vs->type.fat32.label, 11);
1054 set_uuid(id, vs->type.fat32.serno, UUID_DOS);
1057 id->usage_id = VOLUME_ID_FILESYSTEM;
1058 id->type_id = VOLUME_ID_VFAT;
1064 #define UDF_VSD_OFFSET 0x8000
1065 static int probe_udf(struct volume_id *id, __u64 off)
1067 struct volume_descriptor {
1068 struct descriptor_tag {
1077 } __attribute__((__packed__)) tag;
1079 struct anchor_descriptor {
1082 } __attribute__((__packed__)) anchor;
1083 struct primary_descriptor {
1089 } __attribute__((__packed__)) ident;
1090 } __attribute__((__packed__)) primary;
1091 } __attribute__((__packed__)) type;
1092 } __attribute__((__packed__)) *vd;
1094 struct volume_structure_descriptor {
1107 vsd = (struct volume_structure_descriptor *)
1108 get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
1112 if (strncmp(vsd->id, "NSR02", 5) == 0)
1114 if (strncmp(vsd->id, "NSR03", 5) == 0)
1116 if (strncmp(vsd->id, "BEA01", 5) == 0)
1118 if (strncmp(vsd->id, "BOOT2", 5) == 0)
1120 if (strncmp(vsd->id, "CD001", 5) == 0)
1122 if (strncmp(vsd->id, "CDW02", 5) == 0)
1124 if (strncmp(vsd->id, "TEA03", 5) == 0)
1129 /* search the next VSD to get the logical block size of the volume */
1130 for (bs = 0x800; bs < 0x8000; bs += 0x800) {
1131 vsd = (struct volume_structure_descriptor *)
1132 get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
1135 dbg("test for blocksize: 0x%x", bs);
1136 if (vsd->id[0] != '\0')
1142 /* search the list of VSDs for a NSR descriptor */
1143 for (b = 0; b < 64; b++) {
1144 vsd = (struct volume_structure_descriptor *)
1145 get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
1149 dbg("vsd: %c%c%c%c%c",
1150 vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
1152 if (vsd->id[0] == '\0')
1154 if (strncmp(vsd->id, "NSR02", 5) == 0)
1156 if (strncmp(vsd->id, "NSR03", 5) == 0)
1162 /* read anchor volume descriptor */
1163 vd = (struct volume_descriptor *)
1164 get_buffer(id, off + (256 * bs), 0x200);
1168 type = le16_to_cpu(vd->tag.id);
1169 if (type != 2) /* TAG_ID_AVDP */
1172 /* get desriptor list address and block count */
1173 count = le32_to_cpu(vd->type.anchor.length) / bs;
1174 loc = le32_to_cpu(vd->type.anchor.location);
1175 dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
1177 /* pick the primary descriptor from the list */
1178 for (b = 0; b < count; b++) {
1179 vd = (struct volume_descriptor *)
1180 get_buffer(id, off + ((loc + b) * bs), 0x200);
1184 type = le16_to_cpu(vd->tag.id);
1185 dbg("descriptor type %i", type);
1187 /* check validity */
1190 if (le32_to_cpu(vd->tag.location) != loc + b)
1193 if (type == 1) /* TAG_ID_PVD */
1199 set_label_raw(id, &(vd->type.primary.ident.clen), 32);
1201 clen = vd->type.primary.ident.clen;
1202 dbg("label string charsize=%i bit", clen);
1204 set_label_string(id, vd->type.primary.ident.c, 31);
1205 else if (clen == 16)
1206 set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
1209 id->usage_id = VOLUME_ID_FILESYSTEM;
1210 id->type_id = VOLUME_ID_UDF;
1216 #define ISO_SUPERBLOCK_OFFSET 0x8000
1217 static int probe_iso9660(struct volume_id *id, __u64 off)
1219 union iso_super_block {
1227 } __attribute__((__packed__)) iso;
1233 } __attribute__((__packed__)) hs;
1234 } __attribute__((__packed__)) *is;
1236 is = (union iso_super_block *)
1237 get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
1241 if (strncmp(is->iso.id, "CD001", 5) == 0) {
1242 set_label_raw(id, is->iso.volume_id, 32);
1243 set_label_string(id, is->iso.volume_id, 32);
1246 if (strncmp(is->hs.id, "CDROM", 5) == 0)
1251 id->usage_id = VOLUME_ID_FILESYSTEM;
1252 id->type_id = VOLUME_ID_ISO9660;
1253 id->type = "iso9660";
1258 #define UFS_MAGIC 0x00011954
1259 #define UFS2_MAGIC 0x19540119
1260 #define UFS_MAGIC_FEA 0x00195612
1261 #define UFS_MAGIC_LFN 0x00095014
1264 static int probe_ufs(struct volume_id *id, __u64 off)
1266 struct ufs_super_block {
1300 __u32 fs_npsect_state;
1301 __u32 fs_interleave;
1319 } __attribute__((__packed__)) fs_cstotal;
1329 __u32 fs_maxcluster;
1331 __u16 fs_opostbl[16][8];
1332 } __attribute__((__packed__)) fs_u1;
1335 __u8 fs_volname[32];
1340 __u32 fs_contigdirs;
1342 __u32 fs_maxcluster;
1346 __s64 fs_sparecon64[17];
1348 struct ufs2_csum_total {
1353 __u64 cs_numclusters;
1355 } __attribute__((__packed__)) fs_cstotal;
1356 struct ufs_timeval {
1359 } __attribute__((__packed__)) fs_time;
1363 __s64 fs_pendingblocks;
1364 __s32 fs_pendinginodes;
1365 } __attribute__((__packed__)) fs_u2;
1369 __s32 fs_sparecon[53];
1371 __s32 fs_sparecon2[1];
1375 } __attribute__((__packed__)) fs_sun;
1377 __s32 fs_sparecon[53];
1379 __s32 fs_sparecon2[1];
1383 } __attribute__((__packed__)) fs_sunx86;
1385 __s32 fs_sparecon[50];
1386 __s32 fs_contigsumsize;
1387 __s32 fs_maxsymlinklen;
1389 __u32 fs_maxfilesize[2];
1393 } __attribute__((__packed__)) fs_44;
1395 __s32 fs_postblformat;
1401 } __attribute__((__packed__)) *ufs;
1405 int offsets[] = {0, 8, 64, 256, -1};
1407 for (i = 0; offsets[i] >= 0; i++) {
1408 ufs = (struct ufs_super_block *)
1409 get_buffer(id, off + (offsets[i] * 0x400), 0x800);
1413 dbg("offset 0x%x", offsets[i] * 0x400);
1414 magic = be32_to_cpu(ufs->fs_magic);
1415 if ((magic == UFS_MAGIC) ||
1416 (magic == UFS2_MAGIC) ||
1417 (magic == UFS_MAGIC_FEA) ||
1418 (magic == UFS_MAGIC_LFN)) {
1419 dbg("magic 0x%08x(be)", magic);
1422 magic = le32_to_cpu(ufs->fs_magic);
1423 if ((magic == UFS_MAGIC) ||
1424 (magic == UFS2_MAGIC) ||
1425 (magic == UFS_MAGIC_FEA) ||
1426 (magic == UFS_MAGIC_LFN)) {
1427 dbg("magic 0x%08x(le)", magic);
1434 id->usage_id = VOLUME_ID_FILESYSTEM;
1435 id->type_id = VOLUME_ID_UFS;
1441 static int probe_mac_partition_map(struct volume_id *id, __u64 off)
1443 struct mac_driver_desc {
1447 } __attribute__((__packed__)) *driver;
1449 struct mac_partition {
1457 } __attribute__((__packed__)) *part;
1461 buf = get_buffer(id, off, 0x200);
1465 part = (struct mac_partition *) buf;
1466 if ((strncmp(part->signature, "PM", 2) == 0) &&
1467 (strncmp(part->type, "Apple_partition_map", 19) == 0)) {
1468 /* linux creates an own subdevice for the map
1469 * just return the type if the drive header is missing */
1470 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1471 id->type_id = VOLUME_ID_MACPARTMAP;
1472 id->type = "mac_partition_map";
1476 driver = (struct mac_driver_desc *) buf;
1477 if (strncmp(driver->signature, "ER", 2) == 0) {
1478 /* we are on a main device, like a CD
1479 * just try to probe the first partition from the map */
1480 unsigned int bsize = be16_to_cpu(driver->block_size);
1484 /* get first entry of partition table */
1485 buf = get_buffer(id, off + bsize, 0x200);
1489 part = (struct mac_partition *) buf;
1490 if (strncmp(part->signature, "PM", 2) != 0)
1493 part_count = be32_to_cpu(part->map_count);
1494 dbg("expecting %d partition entries", part_count);
1496 if (id->partitions != NULL)
1497 free(id->partitions);
1499 malloc(part_count * sizeof(struct volume_id_partition));
1500 if (id->partitions == NULL)
1502 memset(id->partitions, 0x00, sizeof(struct volume_id_partition));
1504 id->partition_count = part_count;
1506 for (i = 0; i < part_count; i++) {
1510 buf = get_buffer(id, off + ((i+1) * bsize), 0x200);
1514 part = (struct mac_partition *) buf;
1515 if (strncmp(part->signature, "PM", 2) != 0)
1518 poff = be32_to_cpu(part->start_block) * bsize;
1519 plen = be32_to_cpu(part->block_count) * bsize;
1520 dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
1521 part->type, poff, plen);
1523 id->partitions[i].off = poff;
1524 id->partitions[i].len = plen;
1526 if (strncmp(part->type, "Apple_Free", 10) == 0) {
1527 id->partitions[i].usage_id = VOLUME_ID_UNUSED;
1528 } else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
1529 id->partitions[i].usage_id = VOLUME_ID_PARTITIONTABLE;
1530 id->partitions[i].type_id = VOLUME_ID_MACPARTMAP;
1532 id->partitions[i].usage_id = VOLUME_ID_UNPROBED;
1535 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1536 id->type_id = VOLUME_ID_MACPARTMAP;
1537 id->type = "mac_partition_map";
1544 #define HFS_SUPERBLOCK_OFFSET 0x400
1545 #define HFS_NODE_LEAF 0xff
1546 #define HFSPLUS_POR_CNID 1
1547 #define HFSPLUS_EXTENT_COUNT 8
1548 static int probe_hfs_hfsplus(struct volume_id *id, __u64 off)
1550 struct hfs_finder_info{
1558 } __attribute__((__packed__));
1579 __u32 xt_clump_size;
1580 __u32 ct_clump_size;
1581 __u16 num_root_dirs;
1584 struct hfs_finder_info finder_info;
1586 __u16 embed_startblock;
1587 __u16 embed_blockcount;
1588 } __attribute__((__packed__)) *hfs;
1590 struct hfsplus_bnode_descriptor {
1597 } __attribute__((__packed__));
1599 struct hfsplus_bheader_record {
1606 } __attribute__((__packed__));
1608 struct hfsplus_catalog_key {
1612 __u8 unicode[255 * 2];
1613 } __attribute__((__packed__));
1615 struct hfsplus_extent {
1618 } __attribute__((__packed__));
1620 struct hfsplus_fork {
1624 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1625 } __attribute__((__packed__));
1627 struct hfsplus_vol_header {
1631 __u32 last_mount_vers;
1643 __u32 rsrc_clump_sz;
1644 __u32 data_clump_sz;
1647 __u64 encodings_bmp;
1648 struct hfs_finder_info finder_info;
1649 struct hfsplus_fork alloc_file;
1650 struct hfsplus_fork ext_file;
1651 struct hfsplus_fork cat_file;
1652 struct hfsplus_fork attr_file;
1653 struct hfsplus_fork start_file;
1654 } __attribute__((__packed__)) *hfsplus;
1656 unsigned int blocksize;
1657 unsigned int cat_block;
1658 unsigned int ext_block_start;
1659 unsigned int ext_block_count;
1661 unsigned int leaf_node_head;
1662 unsigned int leaf_node_count;
1663 unsigned int leaf_node_size;
1664 unsigned int leaf_block;
1666 unsigned int alloc_block_size;
1667 unsigned int alloc_first_block;
1668 unsigned int embed_first_block;
1669 unsigned int record_count;
1670 struct hfsplus_bnode_descriptor *descr;
1671 struct hfsplus_bheader_record *bnode;
1672 struct hfsplus_catalog_key *key;
1673 unsigned int label_len;
1674 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1677 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1681 hfs = (struct hfs_mdb *) buf;
1682 if (strncmp(hfs->signature, "BD", 2) != 0)
1685 /* it may be just a hfs wrapper for hfs+ */
1686 if (strncmp(hfs->embed_sig, "H+", 2) == 0) {
1687 alloc_block_size = be32_to_cpu(hfs->al_blk_size);
1688 dbg("alloc_block_size 0x%x", alloc_block_size);
1690 alloc_first_block = be16_to_cpu(hfs->al_bl_st);
1691 dbg("alloc_first_block 0x%x", alloc_first_block);
1693 embed_first_block = be16_to_cpu(hfs->embed_startblock);
1694 dbg("embed_first_block 0x%x", embed_first_block);
1696 off += (alloc_first_block * 512) +
1697 (embed_first_block * alloc_block_size);
1698 dbg("hfs wrapped hfs+ found at offset 0x%llx", off);
1700 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1706 if (hfs->label_len > 0 && hfs->label_len < 28) {
1707 set_label_raw(id, hfs->label, hfs->label_len);
1708 set_label_string(id, hfs->label, hfs->label_len) ;
1711 set_uuid(id, hfs->finder_info.id, UUID_HFS);
1713 id->usage_id = VOLUME_ID_FILESYSTEM;
1714 id->type_id = VOLUME_ID_HFS;
1720 hfsplus = (struct hfsplus_vol_header *) buf;
1721 if (strncmp(hfsplus->signature, "H+", 2) == 0)
1723 if (strncmp(hfsplus->signature, "HX", 2) == 0)
1728 set_uuid(id, hfsplus->finder_info.id, UUID_HFS);
1730 blocksize = be32_to_cpu(hfsplus->blocksize);
1731 dbg("blocksize %u", blocksize);
1733 memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
1734 cat_block = be32_to_cpu(extents[0].start_block);
1735 dbg("catalog start block 0x%x", cat_block);
1737 buf = get_buffer(id, off + (cat_block * blocksize), 0x2000);
1741 bnode = (struct hfsplus_bheader_record *)
1742 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1744 leaf_node_head = be32_to_cpu(bnode->leaf_head);
1745 dbg("catalog leaf node 0x%x", leaf_node_head);
1747 leaf_node_size = be16_to_cpu(bnode->node_size);
1748 dbg("leaf node size 0x%x", leaf_node_size);
1750 leaf_node_count = be32_to_cpu(bnode->leaf_count);
1751 dbg("leaf node count 0x%x", leaf_node_count);
1752 if (leaf_node_count == 0)
1755 leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
1757 /* get physical location */
1758 for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
1759 ext_block_start = be32_to_cpu(extents[ext].start_block);
1760 ext_block_count = be32_to_cpu(extents[ext].block_count);
1761 dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
1763 if (ext_block_count == 0)
1766 /* this is our extent */
1767 if (leaf_block < ext_block_count)
1770 leaf_block -= ext_block_count;
1772 if (ext == HFSPLUS_EXTENT_COUNT)
1774 dbg("found block in extent %i", ext);
1776 leaf_off = (ext_block_start + leaf_block) * blocksize;
1778 buf = get_buffer(id, off + leaf_off, leaf_node_size);
1782 descr = (struct hfsplus_bnode_descriptor *) buf;
1783 dbg("descriptor type 0x%x", descr->type);
1785 record_count = be16_to_cpu(descr->num_recs);
1786 dbg("number of records %u", record_count);
1787 if (record_count == 0)
1790 if (descr->type != HFS_NODE_LEAF)
1793 key = (struct hfsplus_catalog_key *)
1794 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1796 dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
1797 if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
1800 label_len = be16_to_cpu(key->unicode_len) * 2;
1801 dbg("label unicode16 len %i", label_len);
1802 set_label_raw(id, key->unicode, label_len);
1803 set_label_unicode16(id, key->unicode, BE, label_len);
1806 id->usage_id = VOLUME_ID_FILESYSTEM;
1807 id->type_id = VOLUME_ID_HFSPLUS;
1808 id->type = "hfsplus";
1813 #define MFT_RECORD_VOLUME 3
1814 #define MFT_RECORD_ATTR_VOLUME_NAME 0x60
1815 #define MFT_RECORD_ATTR_VOLUME_INFO 0x70
1816 #define MFT_RECORD_ATTR_OBJECT_ID 0x40
1817 #define MFT_RECORD_ATTR_END 0xffffffffu
1818 static int probe_ntfs(struct volume_id *id, __u64 off)
1820 struct ntfs_super_block {
1823 __u16 bytes_per_sector;
1824 __u8 sectors_per_cluster;
1825 __u16 reserved_sectors;
1830 __u16 sectors_per_fat;
1831 __u16 sectors_per_track;
1833 __u32 hidden_sectors;
1834 __u32 large_sectors;
1836 __u64 number_of_sectors;
1837 __u64 mft_cluster_location;
1838 __u64 mft_mirror_cluster_location;
1839 __s8 cluster_per_mft_record;
1841 __s8 cluster_per_index_record;
1843 __u8 volume_serial[8];
1845 } __attribute__((__packed__)) *ns;
1847 struct master_file_table_record {
1852 __u16 sequence_number;
1857 __u32 bytes_allocated;
1858 } __attribute__((__packed__)) *mftr;
1860 struct file_attribute {
1870 } __attribute__((__packed__)) *attr;
1872 struct volume_info {
1876 } __attribute__((__packed__)) *info;
1878 unsigned int sector_size;
1879 unsigned int cluster_size;
1882 unsigned int mft_record_size;
1883 unsigned int attr_type;
1884 unsigned int attr_off;
1885 unsigned int attr_len;
1886 unsigned int val_off;
1887 unsigned int val_len;
1891 ns = (struct ntfs_super_block *) get_buffer(id, off, 0x200);
1895 if (strncmp(ns->oem_id, "NTFS", 4) != 0)
1898 set_uuid(id, ns->volume_serial, UUID_NTFS);
1900 sector_size = le16_to_cpu(ns->bytes_per_sector);
1901 cluster_size = ns->sectors_per_cluster * sector_size;
1902 mft_cluster = le64_to_cpu(ns->mft_cluster_location);
1903 mft_off = mft_cluster * cluster_size;
1905 if (ns->cluster_per_mft_record < 0)
1906 /* size = -log2(mft_record_size); normally 1024 Bytes */
1907 mft_record_size = 1 << -ns->cluster_per_mft_record;
1909 mft_record_size = ns->cluster_per_mft_record * cluster_size;
1911 dbg("sectorsize 0x%x", sector_size);
1912 dbg("clustersize 0x%x", cluster_size);
1913 dbg("mftcluster %lli", mft_cluster);
1914 dbg("mftoffset 0x%llx", mft_off);
1915 dbg("cluster per mft_record %i", ns->cluster_per_mft_record);
1916 dbg("mft record size %i", mft_record_size);
1918 buf = get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
1923 mftr = (struct master_file_table_record*) buf;
1925 dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
1926 if (strncmp(mftr->magic, "FILE", 4) != 0)
1929 attr_off = le16_to_cpu(mftr->attrs_offset);
1930 dbg("file $Volume's attributes are at offset %i", attr_off);
1933 attr = (struct file_attribute*) &buf[attr_off];
1934 attr_type = le32_to_cpu(attr->type);
1935 attr_len = le16_to_cpu(attr->len);
1936 val_off = le16_to_cpu(attr->value_offset);
1937 val_len = le32_to_cpu(attr->value_len);
1938 attr_off += attr_len;
1943 if (attr_off >= mft_record_size)
1946 if (attr_type == MFT_RECORD_ATTR_END)
1949 dbg("found attribute type 0x%x, len %i, at offset %i",
1950 attr_type, attr_len, attr_off);
1952 if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
1953 dbg("found info, len %i", val_len);
1954 info = (struct volume_info*) (((__u8 *) attr) + val_off);
1955 snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1,
1956 "%u.%u", info->major_ver, info->minor_ver);
1959 if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
1960 dbg("found label, len %i", val_len);
1961 if (val_len > VOLUME_ID_LABEL_SIZE)
1962 val_len = VOLUME_ID_LABEL_SIZE;
1964 val = ((__u8 *) attr) + val_off;
1965 set_label_raw(id, val, val_len);
1966 set_label_unicode16(id, val, LE, val_len);
1971 id->usage_id = VOLUME_ID_FILESYSTEM;
1972 id->type_id = VOLUME_ID_NTFS;
1978 #define LARGEST_PAGESIZE 0x4000
1979 static int probe_swap(struct volume_id *id, __u64 off)
1984 /* huhh, the swap signature is on the end of the PAGE_SIZE */
1985 for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
1986 sig = get_buffer(id, off + page-10, 10);
1990 if (strncmp(sig, "SWAP-SPACE", 10) == 0) {
1991 strcpy(id->type_version, "1");
1994 if (strncmp(sig, "SWAPSPACE2", 10) == 0) {
1995 strcpy(id->type_version, "2");
2002 id->usage_id = VOLUME_ID_OTHER;
2003 id->type_id = VOLUME_ID_SWAP;
2009 /* probe volume for filesystem type and try to read label+uuid */
2010 int volume_id_probe(struct volume_id *id,
2011 enum volume_id_type type,
2012 unsigned long long off,
2013 unsigned long long size)
2021 case VOLUME_ID_MSDOSPARTTABLE:
2022 rc = probe_msdos_part_table(id, off);
2024 case VOLUME_ID_EXT3:
2025 case VOLUME_ID_EXT2:
2026 rc = probe_ext(id, off);
2028 case VOLUME_ID_REISERFS:
2029 rc = probe_reiserfs(id, off);
2032 rc = probe_xfs(id, off);
2035 rc = probe_jfs(id, off);
2037 case VOLUME_ID_VFAT:
2038 rc = probe_vfat(id, off);
2041 rc = probe_udf(id, off);
2043 case VOLUME_ID_ISO9660:
2044 rc = probe_iso9660(id, off);
2046 case VOLUME_ID_MACPARTMAP:
2047 rc = probe_mac_partition_map(id, off);
2050 case VOLUME_ID_HFSPLUS:
2051 rc = probe_hfs_hfsplus(id, off);
2054 rc = probe_ufs(id, off);
2056 case VOLUME_ID_NTFS:
2057 rc = probe_ntfs(id, off);
2059 case VOLUME_ID_SWAP:
2060 rc = probe_swap(id, off);
2062 case VOLUME_ID_LINUX_RAID:
2063 rc = probe_linux_raid(id, off, size);
2065 case VOLUME_ID_LVM1:
2066 rc = probe_lvm1(id, off);
2068 case VOLUME_ID_LVM2:
2069 rc = probe_lvm2(id, off);
2071 case VOLUME_ID_HPTRAID:
2072 rc = probe_highpoint_ataraid(id, off);
2076 /* probe for raid first, cause fs probes may be successful on raid members */
2077 rc = probe_linux_raid(id, off, size);
2080 rc = probe_lvm1(id, off);
2083 rc = probe_lvm2(id, off);
2086 rc = probe_highpoint_ataraid(id, off);
2090 /* signature in the first block, only small buffer needed */
2091 rc = probe_msdos_part_table(id, off);
2094 rc = probe_vfat(id, off);
2097 rc = probe_mac_partition_map(id, off);
2100 rc = probe_xfs(id, off);
2104 /* fill buffer with maximum */
2105 get_buffer(id, 0, SB_BUFFER_SIZE);
2107 rc = probe_swap(id, off);
2110 rc = probe_ext(id, off);
2113 rc = probe_reiserfs(id, off);
2116 rc = probe_jfs(id, off);
2119 rc = probe_udf(id, off);
2122 rc = probe_iso9660(id, off);
2125 rc = probe_hfs_hfsplus(id, off);
2128 rc = probe_ufs(id, off);
2131 rc = probe_ntfs(id, off);
2138 /* If the filestystem in recognized, we free the allocated buffers,
2139 otherwise they will stay in place for the possible next probe call */
2146 /* open volume by already open file descriptor */
2147 struct volume_id *volume_id_open_fd(int fd)
2149 struct volume_id *id;
2151 id = malloc(sizeof(struct volume_id));
2154 memset(id, 0x00, sizeof(struct volume_id));
2161 /* open volume by device node */
2162 struct volume_id *volume_id_open_node(const char *path)
2164 struct volume_id *id;
2167 fd = open(path, O_RDONLY);
2169 dbg("unable to open '%s'", path);
2173 id = volume_id_open_fd(fd);
2177 /* close fd on device close */
2183 /* open volume by major/minor */
2184 struct volume_id *volume_id_open_dev_t(dev_t devt)
2186 struct volume_id *id;
2187 __u8 tmp_node[VOLUME_ID_PATH_MAX];
2189 snprintf(tmp_node, VOLUME_ID_PATH_MAX,
2190 "/tmp/volume-%u-%u-%u", getpid(), major(devt), minor(devt));
2191 tmp_node[VOLUME_ID_PATH_MAX] = '\0';
2193 /* create tempory node to open the block device */
2195 if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0)
2198 id = volume_id_open_node(tmp_node);
2205 /* free allocated volume info */
2206 void volume_id_close(struct volume_id *id)
2211 if (id->fd_close != 0)
2216 if (id->partitions != NULL)
2217 free(id->partitions);