support for mount by label (not yet tested) Also adds findfs applet. Closes bug 1143.
No binary (build failed)
—
(log yok)
| @@ -452,6 +452,7 @@ libs-y := \ | |
| shell/ \ | |
| sysklogd/ \ | |
| util-linux/ \ | |
| + | util-linux/volume_id/ \ |
| endif # KBUILD_EXTMOD | |
| @@ -557,20 +557,6 @@ static void parse_tune2fs_options(int argc, char **argv) | |
| device_name = x_blkid_get_devname(argv[optind]); | |
| } | |
| - | #ifdef CONFIG_FINDFS |
| - | static ATTRIBUTE_NORETURN void do_findfs(int argc, char **argv) |
| - | { |
| - | if ((argc != 2) || |
| - | (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) |
| - | bb_show_usage(); |
| - | device_name = x_blkid_get_devname(argv[1]); |
| - | puts(device_name); |
| - | exit(0); |
| - | } |
| - | #else |
| - | #define do_findfs(x, y) |
| - | #endif |
| - | |
| static void tune2fs_clean_up(void) | |
| { | |
| if (ENABLE_FEATURE_CLEAN_UP && device_name) free(device_name); | |
| @@ -588,9 +574,7 @@ int tune2fs_main(int argc, char **argv) | |
| if (ENABLE_FEATURE_CLEAN_UP) | |
| atexit(tune2fs_clean_up); | |
| - | if (ENABLE_FINDFS && (applet_name[0] == 'f')) /* findfs */ |
| - | do_findfs(argc, argv); /* no return */ |
| - | else if (ENABLE_E2LABEL && (applet_name[0] == 'e')) /* e2label */ |
| + | if (ENABLE_E2LABEL && (applet_name[0] == 'e')) /* e2label */ |
| parse_e2label_options(argc, argv); | |
| else | |
| parse_tune2fs_options(argc, argv); /* tune2fs */ | |
| @@ -1029,6 +1029,13 @@ USE_FEATURE_BRCTL_FANCY("\n" \ | |
| " -t Get only headers\n" \ | |
| " -z Delete messages on server" | |
| + | #define findfs_trivial_usage \ |
| + | "LABEL=label or UUID=uuid" |
| + | #define findfs_full_usage \ |
| + | "Finds a filesystem device based on a label or UUID." |
| + | #define findfs_example_usage \ |
| + | "$ findfs LABEL=MyDevice" |
| + | |
| #define find_trivial_usage \ | |
| "[PATH...] [EXPRESSION]" | |
| #define find_full_usage \ | |
| @@ -0,0 +1,22 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | char *get_devname_from_label(const char *spec); |
| + | char *get_devname_from_uuid(const char *spec); |
| @@ -150,6 +150,17 @@ config FEATURE_FDISK_ADVANCED | |
| partition, and similarly evil things. Unless you have a very good | |
| reason you would be wise to leave this disabled. | |
| + | config FINDFS |
| + | bool "findfs" |
| + | default n |
| + | select VOLUMEID |
| + | help |
| + | This is similar to the findfs program that is part of the e2fsprogs |
| + | package. However, the e2fsprogs version only support ext2/3. This |
| + | version supports those in addition to FAT, swap, and ReiserFS. |
| + | WARNING: |
| + | With all submodules selected, it will add ~11k to busybox. |
| + | |
| config FREERAMDISK | |
| bool "freeramdisk" | |
| default n | |
| @@ -375,6 +386,215 @@ config FEATURE_USE_TERMIOS | |
| will be unable to determine the current screen size, and will be | |
| unable to move the cursor. | |
| + | config VOLUMEID |
| + | bool "Routines for detecting label and uuid on common filesystems" |
| + | default n |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_EXT |
| + | bool "Ext filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_REISERFS |
| + | bool "Reiser filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_FAT |
| + | bool "fat filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_HFS |
| + | bool "hfs filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_JFS |
| + | bool "jfs filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_UFS |
| + | bool "ufs filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_XFS |
| + | bool "xfs filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_NTFS |
| + | bool "ntfs filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_ISO9660 |
| + | bool "iso9660 filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_UDF |
| + | bool "udf filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_LUKS |
| + | bool "luks filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_LINUXSWAP |
| + | bool "linux swap filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_LVM |
| + | bool "lvm" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_CRAMFS |
| + | bool "cramfs filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_HPFS |
| + | bool "hpfs filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_ROMFS |
| + | bool "romfs filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_SYSV |
| + | bool "sysv filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_MINIX |
| + | bool "minix filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_MAC |
| + | bool "mac filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_MSDOS |
| + | bool "msdos filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_OCFS2 |
| + | bool "ocfs2 filesystem" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_HIGHPOINTRAID |
| + | bool "highpoint raid" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_ISWRAID |
| + | bool "intel raid" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_LSIRAID |
| + | bool "lsi raid" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_VIARAID |
| + | bool "via raid" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_SILICONRAID |
| + | bool "silicon raid" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_NVIDIARAID |
| + | bool "nvidia raid" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_PROMISERAID |
| + | bool "promise raid" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| + | config FEATURE_VOLUMEID_LINUXRAID |
| + | bool "linuxraid" |
| + | default n |
| + | depends on VOLUMEID |
| + | help |
| + | TODO |
| + | |
| config MOUNT | |
| bool "mount" | |
| default n | |
| @@ -414,6 +634,15 @@ config FEATURE_MOUNT_HELPERS | |
| "sometype [-o opts] fs /mnt" if simple mount syscall fails. | |
| The idea is to use such virtual filesystems in /etc/fstab. | |
| + | config FEATURE_MOUNT_LABEL |
| + | bool " Support specifiying devices by label or UUID" |
| + | default n |
| + | depends on MOUNT |
| + | select FINDFS |
| + | help |
| + | This allows for specifying a device by label or uuid, rather than by |
| + | name. This feature utilizes the same functionality as findfs. |
| + | |
| config FEATURE_MOUNT_NFS | |
| bool "Support mounting NFS file systems" | |
| default n | |
| @@ -10,6 +10,7 @@ lib-$(CONFIG_FBSET) +=fbset.o | |
| lib-$(CONFIG_FDFLUSH) +=freeramdisk.o | |
| lib-$(CONFIG_FDFORMAT) +=fdformat.o | |
| lib-$(CONFIG_FDISK) +=fdisk.o | |
| + | lib-$(CONFIG_FINDFS) +=findfs.o |
| lib-$(CONFIG_FREERAMDISK) +=freeramdisk.o | |
| lib-$(CONFIG_FSCK_MINIX) +=fsck_minix.o | |
| lib-$(CONFIG_GETOPT) +=getopt.o | |
| @@ -781,7 +781,7 @@ create_sgilabel(void) | |
| printf(msg_building_new_label, "SGI disklabel"); | |
| - | sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN); |
| + | sgi_other_endian = BB_LITTLE_ENDIAN; |
| res = ioctl(fd, BLKGETSIZE, &longsectors); | |
| if (!ioctl(fd, HDIO_GETGEO, &geometry)) { | |
| g_heads = geometry.heads; | |
| @@ -0,0 +1,38 @@ | |
| + | /* vi: set sw=4 ts=4: */ |
| + | /* |
| + | * Support functions for mounting devices by label/uuid |
| + | * |
| + | * Copyright (C) 2006 by Jason Schoon <[email protected]> |
| + | * Some portions cribbed from e2fsprogs, util-linux, dosfstools |
| + | * |
| + | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| + | */ |
| + | |
| + | #include "libbb.h" |
| + | #include "volume_id.h" |
| + | |
| + | int findfs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| + | int findfs_main(int argc, char **argv) |
| + | { |
| + | char *tmp = NULL; |
| + | |
| + | if (argc != 2) |
| + | bb_show_usage(); |
| + | |
| + | if (!strncmp(argv[1], "LABEL=", 6)) |
| + | tmp = get_devname_from_label(argv[1] + 6); |
| + | else if (!strncmp(argv[1], "UUID=", 5)) |
| + | tmp = get_devname_from_uuid(argv[1] + 5); |
| + | else if (!strncmp(argv[1], "/dev/", 5)) { |
| + | /* Just pass a device name right through. This might aid in some scripts |
| + | being able to call this unconditionally */ |
| + | tmp = argv[1]; |
| + | } else |
| + | bb_show_usage(); |
| + | |
| + | if (tmp) { |
| + | puts(tmp); |
| + | return 0; |
| + | } |
| + | return 1; |
| + | } |
| @@ -19,10 +19,13 @@ | |
| */ | |
| #include <mntent.h> | |
| - | #include "libbb.h" |
| #include <syslog.h> | |
| + | #include "libbb.h" |
| - | /* Needed for nfs support only... */ |
| + | /* For FEATURE_MOUNT_LABEL only */ |
| + | #include "volume_id.h" |
| + | |
| + | /* Needed for nfs support only */ |
| #include <sys/utsname.h> | |
| #undef TRUE | |
| #undef FALSE | |
| @@ -245,6 +248,22 @@ static int verbose_mount(const char *source, const char *target, | |
| #define verbose_mount(...) mount(__VA_ARGS__) | |
| #endif | |
| + | static int resolve_mount_spec(char **fsname) |
| + | { |
| + | char *tmp = NULL; |
| + | |
| + | if (!strncmp(*fsname, "UUID=", 5)) |
| + | tmp = get_devname_from_uuid(*fsname + 5); |
| + | else if (!strncmp(*fsname, "LABEL=", 6)) |
| + | tmp = get_devname_from_label(*fsname + 6); |
| + | |
| + | if (tmp) { |
| + | *fsname = tmp; |
| + | return 1; |
| + | } |
| + | return 0; |
| + | } |
| + | |
| /* Append mount options to string */ | |
| static void append_mount_options(char **oldopts, const char *newopts) | |
| { | |
| @@ -1781,6 +1800,9 @@ int mount_main(int argc, char **argv) | |
| mtpair->mnt_dir = argv[1]; | |
| mtpair->mnt_type = fstype; | |
| mtpair->mnt_opts = cmdopts; | |
| + | if (ENABLE_FEATURE_MOUNT_LABEL) { |
| + | resolve_mount_spec(&mtpair->mnt_fsname); |
| + | } |
| rc = singlemount(mtpair, 0); | |
| goto clean_up; | |
| } | |
| @@ -1842,6 +1864,9 @@ int mount_main(int argc, char **argv) | |
| mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); | |
| append_mount_options(&(mtcur->mnt_opts), cmdopts); | |
| + | if (ENABLE_FEATURE_MOUNT_LABEL) { |
| + | resolve_mount_spec(&mtpair->mnt_fsname); |
| + | } |
| rc = singlemount(mtcur, 0); | |
| free(mtcur->mnt_opts); | |
| } | |
| @@ -1884,6 +1909,9 @@ int mount_main(int argc, char **argv) | |
| bb_error_msg_and_die(must_be_root); | |
| // Mount this thing. | |
| + | if (ENABLE_FEATURE_MOUNT_LABEL) { |
| + | resolve_mount_spec(&mtpair->mnt_fsname); |
| + | } |
| // NFS mounts want this to be xrealloc-able | |
| mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); | |
| @@ -0,0 +1,41 @@ | |
| + | # Makefile for busybox |
| + | # |
| + | # Copyright (C) 1999-2005 by Erik Andersen <[email protected]> |
| + | # |
| + | # Licensed under the GPL v2, see the file LICENSE in this tarball. |
| + | |
| + | lib-y:= |
| + | |
| + | lib-$(CONFIG_FINDFS) += get_devname.o |
| + | lib-$(CONFIG_FEATURE_MOUNT_LABEL) += get_devname.o |
| + | |
| + | lib-$(CONFIG_VOLUMEID) += volume_id.o util.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_EXT) += ext.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_FAT) += fat.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_HFS) += hfs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_HIGHPOINTRAID) += highpoint.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_ISWRAID) += isw_raid.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_LSIRAID) += lsi_raid.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_VIARAID) += via_raid.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_SILICONRAID) += silicon_raid.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_NVIDIARAID) += nvidia_raid.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_PROMISERAID) += promise_raid.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_ISO9660) += iso9660.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_JFS) += jfs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_LINUXRAID) += linux_raid.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_LINUXSWAP) += linux_swap.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_LVM) += lvm.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_MAC) += mac.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_UFS) += ufs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_XFS) += xfs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_CRAMFS) += cramfs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_HPFS) += hpfs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_ROMFS) += romfs.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_SYSV) += sysv.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_MINIX) += minix.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_LUKS) += luks.o |
| + | lib-$(CONFIG_FEATURE_VOLUMEID_OCFS2) += ocfs2.o |
| @@ -0,0 +1,58 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct cramfs_super { |
| + | uint8_t magic[4]; |
| + | uint32_t size; |
| + | uint32_t flags; |
| + | uint32_t future; |
| + | uint8_t signature[16]; |
| + | struct cramfs_info { |
| + | uint32_t crc; |
| + | uint32_t edition; |
| + | uint32_t blocks; |
| + | uint32_t files; |
| + | } __attribute__((__packed__)) info; |
| + | uint8_t name[16]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | int volume_id_probe_cramfs(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct cramfs_super *cs; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | cs = volume_id_get_buffer(id, off, 0x200); |
| + | if (cs == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(cs->magic, "\x45\x3d\xcd\x28", 4) == 0) { |
| + | volume_id_set_label_raw(id, cs->name, 16); |
| + | volume_id_set_label_string(id, cs->name, 16); |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "cramfs"; |
| + | return 0; |
| + | } |
| + | |
| + | return -1; |
| + | } |
| @@ -0,0 +1,71 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct ext2_super_block { |
| + | uint32_t inodes_count; |
| + | uint32_t blocks_count; |
| + | uint32_t r_blocks_count; |
| + | uint32_t free_blocks_count; |
| + | uint32_t free_inodes_count; |
| + | uint32_t first_data_block; |
| + | uint32_t log_block_size; |
| + | uint32_t dummy3[7]; |
| + | uint8_t magic[2]; |
| + | uint16_t state; |
| + | uint32_t dummy5[8]; |
| + | uint32_t feature_compat; |
| + | uint32_t feature_incompat; |
| + | uint32_t feature_ro_compat; |
| + | uint8_t uuid[16]; |
| + | uint8_t volume_name[16]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004 |
| + | #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008 |
| + | #define EXT_SUPERBLOCK_OFFSET 0x400 |
| + | |
| + | int volume_id_probe_ext(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct ext2_super_block *es; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | es = volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200); |
| + | if (es == NULL) |
| + | return -1; |
| + | |
| + | if (es->magic[0] != 0123 || |
| + | es->magic[1] != 0357) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | volume_id_set_label_raw(id, es->volume_name, 16); |
| + | volume_id_set_label_string(id, es->volume_name, 16); |
| + | volume_id_set_uuid(id, es->uuid, UUID_DCE); |
| + | |
| + | if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) |
| + | id->type = "ext3"; |
| + | else |
| + | id->type = "ext2"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,333 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | #define FAT12_MAX 0xff5 |
| + | #define FAT16_MAX 0xfff5 |
| + | #define FAT_ATTR_VOLUME_ID 0x08 |
| + | #define FAT_ATTR_DIR 0x10 |
| + | #define FAT_ATTR_LONG_NAME 0x0f |
| + | #define FAT_ATTR_MASK 0x3f |
| + | #define FAT_ENTRY_FREE 0xe5 |
| + | |
| + | struct vfat_super_block { |
| + | uint8_t boot_jump[3]; |
| + | uint8_t sysid[8]; |
| + | uint16_t sector_size; |
| + | uint8_t sectors_per_cluster; |
| + | uint16_t reserved; |
| + | uint8_t fats; |
| + | uint16_t dir_entries; |
| + | uint16_t sectors; |
| + | uint8_t media; |
| + | uint16_t fat_length; |
| + | uint16_t secs_track; |
| + | uint16_t heads; |
| + | uint32_t hidden; |
| + | uint32_t total_sect; |
| + | union { |
| + | struct fat_super_block { |
| + | uint8_t unknown[3]; |
| + | uint8_t serno[4]; |
| + | uint8_t label[11]; |
| + | uint8_t magic[8]; |
| + | uint8_t dummy2[192]; |
| + | uint8_t pmagic[2]; |
| + | } __attribute__((__packed__)) fat; |
| + | struct fat32_super_block { |
| + | uint32_t fat32_length; |
| + | uint16_t flags; |
| + | uint8_t version[2]; |
| + | uint32_t root_cluster; |
| + | uint16_t insfo_sector; |
| + | uint16_t backup_boot; |
| + | uint16_t reserved2[6]; |
| + | uint8_t unknown[3]; |
| + | uint8_t serno[4]; |
| + | uint8_t label[11]; |
| + | uint8_t magic[8]; |
| + | uint8_t dummy2[164]; |
| + | uint8_t pmagic[2]; |
| + | } __attribute__((__packed__)) fat32; |
| + | } __attribute__((__packed__)) type; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct vfat_dir_entry { |
| + | uint8_t name[11]; |
| + | uint8_t attr; |
| + | uint16_t time_creat; |
| + | uint16_t date_creat; |
| + | uint16_t time_acc; |
| + | uint16_t date_acc; |
| + | uint16_t cluster_high; |
| + | uint16_t time_write; |
| + | uint16_t date_write; |
| + | uint16_t cluster_low; |
| + | uint32_t size; |
| + | } __attribute__((__packed__)); |
| + | |
| + | static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, unsigned count) |
| + | { |
| + | unsigned i; |
| + | |
| + | for (i = 0; i < count; i++) { |
| + | /* end marker */ |
| + | if (dir[i].name[0] == 0x00) { |
| + | dbg("end of dir"); |
| + | break; |
| + | } |
| + | |
| + | /* empty entry */ |
| + | if (dir[i].name[0] == FAT_ENTRY_FREE) |
| + | continue; |
| + | |
| + | /* long name */ |
| + | if ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME) |
| + | continue; |
| + | |
| + | if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { |
| + | /* labels do not have file data */ |
| + | if (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) |
| + | continue; |
| + | |
| + | dbg("found ATTR_VOLUME_ID id in root dir"); |
| + | return dir[i].name; |
| + | } |
| + | |
| + | dbg("skip dir entry"); |
| + | } |
| + | |
| + | return NULL; |
| + | } |
| + | |
| + | int volume_id_probe_vfat(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct vfat_super_block *vs; |
| + | struct vfat_dir_entry *dir; |
| + | uint16_t sector_size; |
| + | uint16_t dir_entries; |
| + | uint32_t sect_count; |
| + | uint16_t reserved; |
| + | uint32_t fat_size; |
| + | uint32_t root_cluster; |
| + | uint32_t dir_size; |
| + | uint32_t cluster_count; |
| + | uint32_t fat_length; |
| + | uint64_t root_start; |
| + | uint32_t start_data_sect; |
| + | uint16_t root_dir_entries; |
| + | uint8_t *buf; |
| + | uint32_t buf_size; |
| + | uint8_t *label = NULL; |
| + | uint32_t next; |
| + | int maxloop; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | vs = volume_id_get_buffer(id, off, 0x200); |
| + | if (vs == NULL) |
| + | return -1; |
| + | |
| + | /* believe only that's fat, don't trust the version |
| + | * the cluster_count will tell us |
| + | */ |
| + | if (memcmp(vs->sysid, "NTFS", 4) == 0) |
| + | return -1; |
| + | |
| + | if (memcmp(vs->type.fat32.magic, "MSWIN", 5) == 0) |
| + | goto valid; |
| + | |
| + | if (memcmp(vs->type.fat32.magic, "FAT32 ", 8) == 0) |
| + | goto valid; |
| + | |
| + | if (memcmp(vs->type.fat.magic, "FAT16 ", 8) == 0) |
| + | goto valid; |
| + | |
| + | if (memcmp(vs->type.fat.magic, "MSDOS", 5) == 0) |
| + | goto valid; |
| + | |
| + | if (memcmp(vs->type.fat.magic, "FAT12 ", 8) == 0) |
| + | goto valid; |
| + | |
| + | /* |
| + | * There are old floppies out there without a magic, so we check |
| + | * for well known values and guess if it's a fat volume |
| + | */ |
| + | |
| + | /* boot jump address check */ |
| + | if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) && |
| + | vs->boot_jump[0] != 0xe9) |
| + | return -1; |
| + | |
| + | /* heads check */ |
| + | if (vs->heads == 0) |
| + | return -1; |
| + | |
| + | /* cluster size check*/ |
| + | if (vs->sectors_per_cluster == 0 || |
| + | (vs->sectors_per_cluster & (vs->sectors_per_cluster-1))) |
| + | return -1; |
| + | |
| + | /* media check */ |
| + | if (vs->media < 0xf8 && vs->media != 0xf0) |
| + | return -1; |
| + | |
| + | /* fat count*/ |
| + | if (vs->fats != 2) |
| + | return -1; |
| + | |
| + | valid: |
| + | /* sector size check */ |
| + | sector_size = le16_to_cpu(vs->sector_size); |
| + | if (sector_size != 0x200 && sector_size != 0x400 && |
| + | sector_size != 0x800 && sector_size != 0x1000) |
| + | return -1; |
| + | |
| + | dbg("sector_size 0x%x", sector_size); |
| + | dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster); |
| + | |
| + | dir_entries = le16_to_cpu(vs->dir_entries); |
| + | reserved = le16_to_cpu(vs->reserved); |
| + | dbg("reserved 0x%x", reserved); |
| + | |
| + | sect_count = le16_to_cpu(vs->sectors); |
| + | if (sect_count == 0) |
| + | sect_count = le32_to_cpu(vs->total_sect); |
| + | dbg("sect_count 0x%x", sect_count); |
| + | |
| + | fat_length = le16_to_cpu(vs->fat_length); |
| + | if (fat_length == 0) |
| + | fat_length = le32_to_cpu(vs->type.fat32.fat32_length); |
| + | dbg("fat_length 0x%x", fat_length); |
| + | |
| + | fat_size = fat_length * vs->fats; |
| + | dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + |
| + | (sector_size-1)) / sector_size; |
| + | dbg("dir_size 0x%x", dir_size); |
| + | |
| + | cluster_count = sect_count - (reserved + fat_size + dir_size); |
| + | cluster_count /= vs->sectors_per_cluster; |
| + | dbg("cluster_count 0x%x", cluster_count); |
| + | |
| + | if (cluster_count < FAT12_MAX) { |
| + | strcpy(id->type_version, "FAT12"); |
| + | } else if (cluster_count < FAT16_MAX) { |
| + | strcpy(id->type_version, "FAT16"); |
| + | } else { |
| + | strcpy(id->type_version, "FAT32"); |
| + | goto fat32; |
| + | } |
| + | |
| + | /* the label may be an attribute in the root directory */ |
| + | root_start = (reserved + fat_size) * sector_size; |
| + | dbg("root dir start 0x%llx", (unsigned long long) root_start); |
| + | root_dir_entries = le16_to_cpu(vs->dir_entries); |
| + | dbg("expected entries 0x%x", root_dir_entries); |
| + | |
| + | buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); |
| + | buf = volume_id_get_buffer(id, off + root_start, buf_size); |
| + | if (buf == NULL) |
| + | goto found; |
| + | |
| + | dir = (struct vfat_dir_entry*) buf; |
| + | |
| + | label = get_attr_volume_id(dir, root_dir_entries); |
| + | |
| + | vs = volume_id_get_buffer(id, off, 0x200); |
| + | if (vs == NULL) |
| + | return -1; |
| + | |
| + | if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) { |
| + | volume_id_set_label_raw(id, label, 11); |
| + | volume_id_set_label_string(id, label, 11); |
| + | } else if (memcmp(vs->type.fat.label, "NO NAME ", 11) != 0) { |
| + | volume_id_set_label_raw(id, vs->type.fat.label, 11); |
| + | volume_id_set_label_string(id, vs->type.fat.label, 11); |
| + | } |
| + | volume_id_set_uuid(id, vs->type.fat.serno, UUID_DOS); |
| + | goto found; |
| + | |
| + | fat32: |
| + | /* FAT32 root dir is a cluster chain like any other directory */ |
| + | buf_size = vs->sectors_per_cluster * sector_size; |
| + | root_cluster = le32_to_cpu(vs->type.fat32.root_cluster); |
| + | dbg("root dir cluster %u", root_cluster); |
| + | start_data_sect = reserved + fat_size; |
| + | |
| + | next = root_cluster; |
| + | maxloop = 100; |
| + | while (--maxloop) { |
| + | uint32_t next_sect_off; |
| + | uint64_t next_off; |
| + | uint64_t fat_entry_off; |
| + | int count; |
| + | |
| + | dbg("next cluster %u", next); |
| + | next_sect_off = (next - 2) * vs->sectors_per_cluster; |
| + | next_off = (start_data_sect + next_sect_off) * sector_size; |
| + | dbg("cluster offset 0x%llx", (unsigned long long) next_off); |
| + | |
| + | /* get cluster */ |
| + | buf = volume_id_get_buffer(id, off + next_off, buf_size); |
| + | if (buf == NULL) |
| + | goto found; |
| + | |
| + | dir = (struct vfat_dir_entry*) buf; |
| + | count = buf_size / sizeof(struct vfat_dir_entry); |
| + | dbg("expected entries 0x%x", count); |
| + | |
| + | label = get_attr_volume_id(dir, count); |
| + | if (label) |
| + | break; |
| + | |
| + | /* get FAT entry */ |
| + | fat_entry_off = (reserved * sector_size) + (next * sizeof(uint32_t)); |
| + | buf = volume_id_get_buffer(id, off + fat_entry_off, buf_size); |
| + | if (buf == NULL) |
| + | goto found; |
| + | |
| + | /* set next cluster */ |
| + | next = le32_to_cpu(*((uint32_t *) buf) & 0x0fffffff); |
| + | if (next == 0) |
| + | break; |
| + | } |
| + | if (maxloop == 0) |
| + | dbg("reached maximum follow count of root cluster chain, give up"); |
| + | |
| + | vs = volume_id_get_buffer(id, off, 0x200); |
| + | if (vs == NULL) |
| + | return -1; |
| + | |
| + | if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) { |
| + | volume_id_set_label_raw(id, label, 11); |
| + | volume_id_set_label_string(id, label, 11); |
| + | } else if (memcmp(vs->type.fat32.label, "NO NAME ", 11) != 0) { |
| + | volume_id_set_label_raw(id, vs->type.fat32.label, 11); |
| + | volume_id_set_label_string(id, vs->type.fat32.label, 11); |
| + | } |
| + | volume_id_set_uuid(id, vs->type.fat32.serno, UUID_DOS); |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "vfat"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,399 @@ | |
| + | /* vi: set sw=4 ts=4: */ |
| + | /* |
| + | * Support functions for mounting devices by label/uuid |
| + | * |
| + | * Copyright (C) 2006 by Jason Schoon <[email protected]> |
| + | * Some portions cribbed from e2fsprogs, util-linux, dosfstools |
| + | * |
| + | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | #define BLKGETSIZE64 _IOR(0x12,114,size_t) |
| + | |
| + | #define PROC_PARTITIONS "/proc/partitions" |
| + | #define PROC_CDROMS "/proc/sys/dev/cdrom/info" |
| + | #define DEVLABELDIR "/dev" |
| + | #define SYS_BLOCK "/sys/block" |
| + | |
| + | static struct uuidCache_s { |
| + | struct uuidCache_s *next; |
| + | char uuid[16]; |
| + | char *device; |
| + | char *label; |
| + | int major, minor; |
| + | } *uuidCache; |
| + | |
| + | /* for now, only ext2, ext3 and xfs are supported */ |
| + | static int |
| + | get_label_uuid(const char *device, char **label, char **uuid, int iso_only) |
| + | { |
| + | int rv = 1; |
| + | uint64_t size; |
| + | struct volume_id *vid; |
| + | |
| + | vid = volume_id_open_node(device); |
| + | |
| + | if (ioctl(vid->fd, BLKGETSIZE64, &size) != 0) { |
| + | size = 0; |
| + | } |
| + | |
| + | #if ENABLE_FEATURE_VOLUMEID_ISO9660 |
| + | if (iso_only ? |
| + | volume_id_probe_iso9660(vid, 0) != 0 : |
| + | volume_id_probe_all(vid, 0, size) != 0) { |
| + | goto ret; |
| + | } |
| + | #else |
| + | if (volume_id_probe_all(vid, 0, size) != 0) { |
| + | goto ret; |
| + | } |
| + | #endif |
| + | |
| + | if (vid->label[0] != '\0') { |
| + | *label = xstrndup(vid->label, sizeof(vid->label)); |
| + | *uuid = xstrndup(vid->uuid, sizeof(vid->uuid)); |
| + | printf("Found label %s on %s (uuid:%s)\n", *label, device, *uuid); |
| + | rv = 0; |
| + | } |
| + | ret: |
| + | free_volume_id(vid); |
| + | return rv; |
| + | } |
| + | |
| + | static void |
| + | uuidcache_addentry(char * device, int major, int minor, char *label, char *uuid) |
| + | { |
| + | struct uuidCache_s *last; |
| + | |
| + | if (!uuidCache) { |
| + | last = uuidCache = xzalloc(sizeof(*uuidCache)); |
| + | } else { |
| + | for (last = uuidCache; last->next; last = last->next) |
| + | continue; |
| + | last->next = xzalloc(sizeof(*uuidCache)); |
| + | last = last->next; |
| + | } |
| + | /*last->next = NULL; - xzalloc did it*/ |
| + | last->label = label; |
| + | last->device = device; |
| + | last->major = major; |
| + | last->minor = minor; |
| + | memcpy(last->uuid, uuid, sizeof(last->uuid)); |
| + | } |
| + | |
| + | static void |
| + | uuidcache_check_device(const char *device_name, int ma, int mi, int iso_only) |
| + | { |
| + | char device[110]; |
| + | char *uuid = NULL, *label = NULL; |
| + | char *ptr; |
| + | char *deviceDir = NULL; |
| + | int mustRemove = 0; |
| + | int mustRemoveDir = 0; |
| + | int i; |
| + | |
| + | sprintf(device, "%s/%s", DEVLABELDIR, device_name); |
| + | if (access(device, F_OK)) { |
| + | ptr = device; |
| + | i = 0; |
| + | while (*ptr) |
| + | if (*ptr++ == '/') |
| + | i++; |
| + | if (i > 2) { |
| + | deviceDir = alloca(strlen(device) + 1); |
| + | strcpy(deviceDir, device); |
| + | ptr = deviceDir + (strlen(device) - 1); |
| + | while (*ptr != '/') |
| + | *ptr-- = '\0'; |
| + | if (mkdir(deviceDir, 0644)) { |
| + | printf("mkdir: cannot create directory %s: %d\n", deviceDir, errno); |
| + | } else { |
| + | mustRemoveDir = 1; |
| + | } |
| + | } |
| + | |
| + | mknod(device, S_IFBLK | 0600, makedev(ma, mi)); |
| + | mustRemove = 1; |
| + | } |
| + | if (!get_label_uuid(device, &label, &uuid, iso_only)) |
| + | uuidcache_addentry(strdup(device), ma, mi, |
| + | label, uuid); |
| + | |
| + | if (mustRemove) unlink(device); |
| + | if (mustRemoveDir) rmdir(deviceDir); |
| + | } |
| + | |
| + | static void |
| + | uuidcache_init_partitions(void) |
| + | { |
| + | char line[100]; |
| + | int ma, mi; |
| + | unsigned long long sz; |
| + | FILE *procpt; |
| + | int firstPass; |
| + | int handleOnFirst; |
| + | char *chptr; |
| + | |
| + | procpt = xfopen(PROC_PARTITIONS, "r"); |
| + | /* |
| + | # cat /proc/partitions |
| + | major minor #blocks name |
| + | |
| + | 8 0 293036184 sda |
| + | 8 1 6835626 sda1 |
| + | 8 2 1 sda2 |
| + | 8 5 979933 sda5 |
| + | 8 6 15623181 sda6 |
| + | 8 7 97659103 sda7 |
| + | 8 8 171935631 sda8 |
| + | */ |
| + | for (firstPass = 1; firstPass >= 0; firstPass--) { |
| + | fseek(procpt, 0, SEEK_SET); |
| + | |
| + | while (fgets(line, sizeof(line), procpt)) { |
| + | /* The original version of this code used sscanf, but |
| + | diet's sscanf is quite limited */ |
| + | chptr = line; |
| + | if (*chptr != ' ') continue; |
| + | chptr++; |
| + | |
| + | ma = bb_strtou(chptr, &chptr, 0); |
| + | if (ma < 0) continue; |
| + | chptr = skip_whitespace(chptr); |
| + | |
| + | mi = bb_strtou(chptr, &chptr, 0); |
| + | if (mi < 0) continue; |
| + | chptr = skip_whitespace(chptr); |
| + | |
| + | sz = bb_strtoull(chptr, &chptr, 0); |
| + | if ((long long)sz == -1LL) continue; |
| + | chptr = skip_whitespace(chptr); |
| + | |
| + | /* skip extended partitions (heuristic: size 1) */ |
| + | if (sz == 1) |
| + | continue; |
| + | |
| + | *strchrnul(chptr, '\n') = '\0'; |
| + | /* now chptr => device name */ |
| + | if (!chptr[0]) |
| + | continue; |
| + | |
| + | /* look only at md devices on first pass */ |
| + | handleOnFirst = (chptr[0] == 'm' && chptr[1] == 'd'); |
| + | if (firstPass != handleOnFirst) |
| + | continue; |
| + | |
| + | /* heuristic: partition name ends in a digit */ |
| + | if (isdigit(chptr[strlen(chptr) - 1])) { |
| + | uuidcache_check_device(chptr, ma, mi, 0); |
| + | } |
| + | } |
| + | } |
| + | |
| + | fclose(procpt); |
| + | } |
| + | |
| + | static int |
| + | dev_get_major_minor(char *device_name, int *major, int *minor) |
| + | { |
| + | char * dev_path; |
| + | int fd; |
| + | char dev[7]; |
| + | char *major_ptr, *minor_ptr; |
| + | |
| + | dev_path = alloca(strlen(SYS_BLOCK) + strlen(device_name) + 6); |
| + | sprintf(dev_path, "%s/%s/dev", SYS_BLOCK, device_name); |
| + | |
| + | fd = open(dev_path, O_RDONLY); |
| + | if (fd < 0) return 1; |
| + | full_read(fd, dev, sizeof(dev)); |
| + | close(fd); |
| + | |
| + | major_ptr = dev; |
| + | minor_ptr = strchr(dev, ':'); |
| + | if (!minor_ptr) return 1; |
| + | *minor_ptr++ = '\0'; |
| + | |
| + | *major = strtol(major_ptr, NULL, 10); |
| + | *minor = strtol(minor_ptr, NULL, 10); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | static void |
| + | uuidcache_init_cdroms(void) |
| + | { |
| + | char line[100]; |
| + | int ma, mi; |
| + | FILE *proccd; |
| + | |
| + | proccd = fopen(PROC_CDROMS, "r"); |
| + | if (!proccd) { |
| + | static smallint warn = 0; |
| + | if (!warn) { |
| + | warn = 1; |
| + | bb_error_msg("mount: could not open %s, so UUID and LABEL " |
| + | "conversion cannot be done for CD-Roms.", |
| + | PROC_CDROMS); |
| + | } |
| + | return; |
| + | } |
| + | |
| + | while (fgets(line, sizeof(line), proccd)) { |
| + | const char *drive_name_string = "drive name:\t\t"; |
| + | if (!strncmp(line, drive_name_string, strlen(drive_name_string))) { |
| + | char *device_name; |
| + | device_name = strtok(line + strlen(drive_name_string), "\t\n"); |
| + | while (device_name) { |
| + | dev_get_major_minor(device_name, &ma, &mi); |
| + | uuidcache_check_device(device_name, ma, mi, 1); |
| + | device_name = strtok(NULL, "\t\n"); |
| + | } |
| + | break; |
| + | } |
| + | } |
| + | |
| + | fclose(proccd); |
| + | } |
| + | |
| + | static void |
| + | uuidcache_init(void) |
| + | { |
| + | if (uuidCache) |
| + | return; |
| + | |
| + | uuidcache_init_partitions(); |
| + | uuidcache_init_cdroms(); |
| + | } |
| + | |
| + | #define UUID 1 |
| + | #define VOL 2 |
| + | |
| + | #ifdef UNUSED |
| + | static char * |
| + | get_spec_by_x(int n, const char *t, int * majorPtr, int * minorPtr) |
| + | { |
| + | struct uuidCache_s *uc; |
| + | |
| + | uuidcache_init(); |
| + | uc = uuidCache; |
| + | |
| + | while(uc) { |
| + | switch (n) { |
| + | case UUID: |
| + | if (!memcmp(t, uc->uuid, sizeof(uc->uuid))) { |
| + | *majorPtr = uc->major; |
| + | *minorPtr = uc->minor; |
| + | return uc->device; |
| + | } |
| + | break; |
| + | case VOL: |
| + | if (!strcmp(t, uc->label)) { |
| + | *majorPtr = uc->major; |
| + | *minorPtr = uc->minor; |
| + | return uc->device; |
| + | } |
| + | break; |
| + | } |
| + | uc = uc->next; |
| + | } |
| + | return NULL; |
| + | } |
| + | |
| + | static unsigned char |
| + | fromhex(char c) |
| + | { |
| + | if (isdigit(c)) |
| + | return (c - '0'); |
| + | if (islower(c)) |
| + | return (c - 'a' + 10); |
| + | return (c - 'A' + 10); |
| + | } |
| + | |
| + | static char * |
| + | get_spec_by_uuid(const char *s, int * major, int * minor) |
| + | { |
| + | unsigned char uuid[16]; |
| + | int i; |
| + | |
| + | if (strlen(s) != 36 || |
| + | s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') |
| + | goto bad_uuid; |
| + | for (i=0; i<16; i++) { |
| + | if (*s == '-') s++; |
| + | if (!isxdigit(s[0]) || !isxdigit(s[1])) |
| + | goto bad_uuid; |
| + | uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1])); |
| + | s += 2; |
| + | } |
| + | return get_spec_by_x(UUID, (char *)uuid, major, minor); |
| + | |
| + | bad_uuid: |
| + | fprintf(stderr, _("mount: bad UUID")); |
| + | return 0; |
| + | } |
| + | |
| + | static char * |
| + | get_spec_by_volume_label(const char *s, int *major, int *minor) |
| + | { |
| + | return get_spec_by_x(VOL, s, major, minor); |
| + | } |
| + | |
| + | static int display_uuid_cache(void) |
| + | { |
| + | struct uuidCache_s *u; |
| + | size_t i; |
| + | |
| + | uuidcache_init(); |
| + | |
| + | u = uuidCache; |
| + | while (u) { |
| + | printf("%s %s ", u->device, u->label); |
| + | for (i = 0; i < sizeof(u->uuid); i++) { |
| + | if (i == 4 || i == 6 || i == 8 || i == 10) |
| + | printf("-"); |
| + | printf("%x", u->uuid[i] & 0xff); |
| + | } |
| + | printf("\n"); |
| + | u = u->next; |
| + | } |
| + | |
| + | return 0; |
| + | } |
| + | #endif // UNUSED |
| + | |
| + | |
| + | /* Used by mount and findfs */ |
| + | |
| + | char *get_devname_from_label(const char *spec) |
| + | { |
| + | struct uuidCache_s *uc; |
| + | int spec_len = strlen(spec); |
| + | |
| + | uuidcache_init(); |
| + | uc = uuidCache; |
| + | while (uc) { |
| + | if (uc->label && !strncmp(spec, uc->label, spec_len)) { |
| + | return xstrdup(uc->device); |
| + | } |
| + | uc = uc->next; |
| + | } |
| + | return NULL; |
| + | } |
| + | |
| + | char *get_devname_from_uuid(const char *spec) |
| + | { |
| + | struct uuidCache_s *uc; |
| + | |
| + | uuidcache_init(); |
| + | uc = uuidCache; |
| + | while (uc) { |
| + | if (!memcmp(spec, uc->uuid, sizeof(uc->uuid))) { |
| + | return xstrdup(uc->device); |
| + | } |
| + | uc = uc->next; |
| + | } |
| + | return NULL; |
| + | } |
| @@ -0,0 +1,292 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct hfs_finder_info{ |
| + | uint32_t boot_folder; |
| + | uint32_t start_app; |
| + | uint32_t open_folder; |
| + | uint32_t os9_folder; |
| + | uint32_t reserved; |
| + | uint32_t osx_folder; |
| + | uint8_t id[8]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct hfs_mdb { |
| + | uint8_t signature[2]; |
| + | uint32_t cr_date; |
| + | uint32_t ls_Mod; |
| + | uint16_t atrb; |
| + | uint16_t nm_fls; |
| + | uint16_t vbm_st; |
| + | uint16_t alloc_ptr; |
| + | uint16_t nm_al_blks; |
| + | uint32_t al_blk_size; |
| + | uint32_t clp_size; |
| + | uint16_t al_bl_st; |
| + | uint32_t nxt_cnid; |
| + | uint16_t free_bks; |
| + | uint8_t label_len; |
| + | uint8_t label[27]; |
| + | uint32_t vol_bkup; |
| + | uint16_t vol_seq_num; |
| + | uint32_t wr_cnt; |
| + | uint32_t xt_clump_size; |
| + | uint32_t ct_clump_size; |
| + | uint16_t num_root_dirs; |
| + | uint32_t file_count; |
| + | uint32_t dir_count; |
| + | struct hfs_finder_info finder_info; |
| + | uint8_t embed_sig[2]; |
| + | uint16_t embed_startblock; |
| + | uint16_t embed_blockcount; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct hfsplus_bnode_descriptor { |
| + | uint32_t next; |
| + | uint32_t prev; |
| + | uint8_t type; |
| + | uint8_t height; |
| + | uint16_t num_recs; |
| + | uint16_t reserved; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct hfsplus_bheader_record { |
| + | uint16_t depth; |
| + | uint32_t root; |
| + | uint32_t leaf_count; |
| + | uint32_t leaf_head; |
| + | uint32_t leaf_tail; |
| + | uint16_t node_size; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct hfsplus_catalog_key { |
| + | uint16_t key_len; |
| + | uint32_t parent_id; |
| + | uint16_t unicode_len; |
| + | uint8_t unicode[255 * 2]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct hfsplus_extent { |
| + | uint32_t start_block; |
| + | uint32_t block_count; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define HFSPLUS_EXTENT_COUNT 8 |
| + | struct hfsplus_fork { |
| + | uint64_t total_size; |
| + | uint32_t clump_size; |
| + | uint32_t total_blocks; |
| + | struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct hfsplus_vol_header { |
| + | uint8_t signature[2]; |
| + | uint16_t version; |
| + | uint32_t attributes; |
| + | uint32_t last_mount_vers; |
| + | uint32_t reserved; |
| + | uint32_t create_date; |
| + | uint32_t modify_date; |
| + | uint32_t backup_date; |
| + | uint32_t checked_date; |
| + | uint32_t file_count; |
| + | uint32_t folder_count; |
| + | uint32_t blocksize; |
| + | uint32_t total_blocks; |
| + | uint32_t free_blocks; |
| + | uint32_t next_alloc; |
| + | uint32_t rsrc_clump_sz; |
| + | uint32_t data_clump_sz; |
| + | uint32_t next_cnid; |
| + | uint32_t write_count; |
| + | uint64_t encodings_bmp; |
| + | struct hfs_finder_info finder_info; |
| + | struct hfsplus_fork alloc_file; |
| + | struct hfsplus_fork ext_file; |
| + | struct hfsplus_fork cat_file; |
| + | struct hfsplus_fork attr_file; |
| + | struct hfsplus_fork start_file; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define HFS_SUPERBLOCK_OFFSET 0x400 |
| + | #define HFS_NODE_LEAF 0xff |
| + | #define HFSPLUS_POR_CNID 1 |
| + | |
| + | int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off) |
| + | { |
| + | unsigned blocksize; |
| + | unsigned cat_block; |
| + | unsigned ext_block_start; |
| + | unsigned ext_block_count; |
| + | int ext; |
| + | unsigned leaf_node_head; |
| + | unsigned leaf_node_count; |
| + | unsigned leaf_node_size; |
| + | unsigned leaf_block; |
| + | uint64_t leaf_off; |
| + | unsigned alloc_block_size; |
| + | unsigned alloc_first_block; |
| + | unsigned embed_first_block; |
| + | unsigned record_count; |
| + | struct hfsplus_vol_header *hfsplus; |
| + | struct hfsplus_bnode_descriptor *descr; |
| + | struct hfsplus_bheader_record *bnode; |
| + | struct hfsplus_catalog_key *key; |
| + | unsigned label_len; |
| + | struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; |
| + | struct hfs_mdb *hfs; |
| + | const uint8_t *buf; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | hfs = (struct hfs_mdb *) buf; |
| + | if (hfs->signature[0] != 'B' || hfs->signature[1] != 'D') |
| + | goto checkplus; |
| + | |
| + | /* it may be just a hfs wrapper for hfs+ */ |
| + | if (memcmp(hfs->embed_sig, "H+", 2) == 0) { |
| + | alloc_block_size = be32_to_cpu(hfs->al_blk_size); |
| + | dbg("alloc_block_size 0x%x", alloc_block_size); |
| + | |
| + | alloc_first_block = be16_to_cpu(hfs->al_bl_st); |
| + | dbg("alloc_first_block 0x%x", alloc_first_block); |
| + | |
| + | embed_first_block = be16_to_cpu(hfs->embed_startblock); |
| + | dbg("embed_first_block 0x%x", embed_first_block); |
| + | |
| + | off += (alloc_first_block * 512) + |
| + | (embed_first_block * alloc_block_size); |
| + | dbg("hfs wrapped hfs+ found at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200); |
| + | if (buf == NULL) |
| + | return -1; |
| + | goto checkplus; |
| + | } |
| + | |
| + | if (hfs->label_len > 0 && hfs->label_len < 28) { |
| + | volume_id_set_label_raw(id, hfs->label, hfs->label_len); |
| + | volume_id_set_label_string(id, hfs->label, hfs->label_len) ; |
| + | } |
| + | |
| + | volume_id_set_uuid(id, hfs->finder_info.id, UUID_HFS); |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "hfs"; |
| + | |
| + | return 0; |
| + | |
| + | checkplus: |
| + | hfsplus = (struct hfsplus_vol_header *) buf; |
| + | if (hfs->signature[0] == 'H') |
| + | if (hfs->signature[1] == '+' || hfs->signature[1] == 'X') |
| + | goto hfsplus; |
| + | return -1; |
| + | |
| + | hfsplus: |
| + | volume_id_set_uuid(id, hfsplus->finder_info.id, UUID_HFS); |
| + | |
| + | blocksize = be32_to_cpu(hfsplus->blocksize); |
| + | dbg("blocksize %u", blocksize); |
| + | |
| + | memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); |
| + | cat_block = be32_to_cpu(extents[0].start_block); |
| + | dbg("catalog start block 0x%x", cat_block); |
| + | |
| + | buf = volume_id_get_buffer(id, off + (cat_block * blocksize), 0x2000); |
| + | if (buf == NULL) |
| + | goto found; |
| + | |
| + | bnode = (struct hfsplus_bheader_record *) |
| + | &buf[sizeof(struct hfsplus_bnode_descriptor)]; |
| + | |
| + | leaf_node_head = be32_to_cpu(bnode->leaf_head); |
| + | dbg("catalog leaf node 0x%x", leaf_node_head); |
| + | |
| + | leaf_node_size = be16_to_cpu(bnode->node_size); |
| + | dbg("leaf node size 0x%x", leaf_node_size); |
| + | |
| + | leaf_node_count = be32_to_cpu(bnode->leaf_count); |
| + | dbg("leaf node count 0x%x", leaf_node_count); |
| + | if (leaf_node_count == 0) |
| + | goto found; |
| + | |
| + | leaf_block = (leaf_node_head * leaf_node_size) / blocksize; |
| + | |
| + | /* get physical location */ |
| + | for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { |
| + | ext_block_start = be32_to_cpu(extents[ext].start_block); |
| + | ext_block_count = be32_to_cpu(extents[ext].block_count); |
| + | dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count); |
| + | |
| + | if (ext_block_count == 0) |
| + | goto found; |
| + | |
| + | /* this is our extent */ |
| + | if (leaf_block < ext_block_count) |
| + | break; |
| + | |
| + | leaf_block -= ext_block_count; |
| + | } |
| + | if (ext == HFSPLUS_EXTENT_COUNT) |
| + | goto found; |
| + | dbg("found block in extent %i", ext); |
| + | |
| + | leaf_off = (ext_block_start + leaf_block) * blocksize; |
| + | |
| + | buf = volume_id_get_buffer(id, off + leaf_off, leaf_node_size); |
| + | if (buf == NULL) |
| + | goto found; |
| + | |
| + | descr = (struct hfsplus_bnode_descriptor *) buf; |
| + | dbg("descriptor type 0x%x", descr->type); |
| + | |
| + | record_count = be16_to_cpu(descr->num_recs); |
| + | dbg("number of records %u", record_count); |
| + | if (record_count == 0) |
| + | goto found; |
| + | |
| + | if (descr->type != HFS_NODE_LEAF) |
| + | goto found; |
| + | |
| + | key = (struct hfsplus_catalog_key *) |
| + | &buf[sizeof(struct hfsplus_bnode_descriptor)]; |
| + | |
| + | dbg("parent id 0x%x", be32_to_cpu(key->parent_id)); |
| + | if (key->parent_id != cpu_to_be32(HFSPLUS_POR_CNID)) |
| + | goto found; |
| + | |
| + | label_len = be16_to_cpu(key->unicode_len) * 2; |
| + | dbg("label unicode16 len %i", label_len); |
| + | volume_id_set_label_raw(id, key->unicode, label_len); |
| + | volume_id_set_label_unicode16(id, key->unicode, BE, label_len); |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "hfsplus"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,86 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct hpt37x_meta { |
| + | uint8_t filler1[32]; |
| + | uint32_t magic; |
| + | } __attribute__((packed)); |
| + | |
| + | struct hpt45x_meta { |
| + | uint32_t magic; |
| + | } __attribute__((packed)); |
| + | |
| + | #define HPT37X_CONFIG_OFF 0x1200 |
| + | #define HPT37X_MAGIC_OK 0x5a7816f0 |
| + | #define HPT37X_MAGIC_BAD 0x5a7816fd |
| + | |
| + | #define HPT45X_MAGIC_OK 0x5a7816f3 |
| + | #define HPT45X_MAGIC_BAD 0x5a7816fd |
| + | |
| + | |
| + | int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct hpt37x_meta *hpt; |
| + | uint32_t magic; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | hpt = volume_id_get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200); |
| + | if (hpt == NULL) |
| + | return -1; |
| + | |
| + | magic = hpt->magic; |
| + | if (magic != cpu_to_le32(HPT37X_MAGIC_OK) && magic != cpu_to_le32(HPT37X_MAGIC_BAD)) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | id->type = "highpoint_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | struct hpt45x_meta *hpt; |
| + | uint64_t meta_off; |
| + | uint32_t magic; |
| + | |
| + | dbg("probing at offset 0x%llx, size 0x%llx", |
| + | (unsigned long long) off, (unsigned long long) size); |
| + | |
| + | if (size < 0x10000) |
| + | return -1; |
| + | |
| + | meta_off = ((size / 0x200)-11) * 0x200; |
| + | hpt = volume_id_get_buffer(id, off + meta_off, 0x200); |
| + | if (hpt == NULL) |
| + | return -1; |
| + | |
| + | magic = hpt->magic; |
| + | if (magic != cpu_to_le32(HPT45X_MAGIC_OK) && magic != cpu_to_le32(HPT45X_MAGIC_BAD)) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | id->type = "highpoint_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,50 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct hpfs_super |
| + | { |
| + | uint8_t magic[4]; |
| + | uint8_t version; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define HPFS_SUPERBLOCK_OFFSET 0x2000 |
| + | |
| + | int volume_id_probe_hpfs(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct hpfs_super *hs; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | hs = volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_OFFSET, 0x200); |
| + | if (hs == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(hs->magic, "\x49\xe8\x95\xf9", 4) == 0) { |
| + | sprintf(id->type_version, "%u", hs->version); |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "hpfs"; |
| + | return 0; |
| + | } |
| + | |
| + | return -1; |
| + | } |
| @@ -0,0 +1,118 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | #define ISO_SUPERBLOCK_OFFSET 0x8000 |
| + | #define ISO_SECTOR_SIZE 0x800 |
| + | #define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE) |
| + | #define ISO_VD_PRIMARY 0x1 |
| + | #define ISO_VD_SUPPLEMENTARY 0x2 |
| + | #define ISO_VD_END 0xff |
| + | #define ISO_VD_MAX 16 |
| + | |
| + | struct iso_volume_descriptor { |
| + | uint8_t vd_type; |
| + | uint8_t vd_id[5]; |
| + | uint8_t vd_version; |
| + | uint8_t flags; |
| + | uint8_t system_id[32]; |
| + | uint8_t volume_id[32]; |
| + | uint8_t unused[8]; |
| + | uint8_t space_size[8]; |
| + | uint8_t escape_sequences[8]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct high_sierra_volume_descriptor { |
| + | uint8_t foo[8]; |
| + | uint8_t type; |
| + | uint8_t id[4]; |
| + | uint8_t version; |
| + | } __attribute__((__packed__)); |
| + | |
| + | int volume_id_probe_iso9660(struct volume_id *id, uint64_t off) |
| + | { |
| + | uint8_t *buf; |
| + | struct iso_volume_descriptor *is; |
| + | struct high_sierra_volume_descriptor *hs; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | buf = volume_id_get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | is = (struct iso_volume_descriptor *) buf; |
| + | |
| + | if (memcmp(is->vd_id, "CD001", 5) == 0) { |
| + | int vd_offset; |
| + | int i; |
| + | |
| + | dbg("read label from PVD"); |
| + | volume_id_set_label_raw(id, is->volume_id, 32); |
| + | volume_id_set_label_string(id, is->volume_id, 32); |
| + | |
| + | dbg("looking for SVDs"); |
| + | vd_offset = ISO_VD_OFFSET; |
| + | for (i = 0; i < ISO_VD_MAX; i++) { |
| + | uint8_t svd_label[64]; |
| + | |
| + | is = volume_id_get_buffer(id, off + vd_offset, 0x200); |
| + | if (is == NULL || is->vd_type == ISO_VD_END) |
| + | break; |
| + | if (is->vd_type != ISO_VD_SUPPLEMENTARY) |
| + | continue; |
| + | |
| + | dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset)); |
| + | if (memcmp(is->escape_sequences, "%/@", 3) == 0|| |
| + | memcmp(is->escape_sequences, "%/C", 3) == 0|| |
| + | memcmp(is->escape_sequences, "%/E", 3) == 0) { |
| + | dbg("Joliet extension found"); |
| + | volume_id_set_unicode16((char *)svd_label, sizeof(svd_label), is->volume_id, BE, 32); |
| + | if (memcmp(id->label, svd_label, 16) == 0) { |
| + | dbg("SVD label is identical, use the possibly longer PVD one"); |
| + | break; |
| + | } |
| + | |
| + | volume_id_set_label_raw(id, is->volume_id, 32); |
| + | volume_id_set_label_string(id, svd_label, 32); |
| + | strcpy(id->type_version, "Joliet Extension"); |
| + | goto found; |
| + | } |
| + | vd_offset += ISO_SECTOR_SIZE; |
| + | } |
| + | goto found; |
| + | } |
| + | |
| + | hs = (struct high_sierra_volume_descriptor *) buf; |
| + | |
| + | if (memcmp(hs->id, "CDROM", 5) == 0) { |
| + | strcpy(id->type_version, "High Sierra"); |
| + | goto found; |
| + | } |
| + | |
| + | return -1; |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "iso9660"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,58 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct isw_meta { |
| + | uint8_t sig[32]; |
| + | uint32_t check_sum; |
| + | uint32_t mpb_size; |
| + | uint32_t family_num; |
| + | uint32_t generation_num; |
| + | } __attribute__((packed)); |
| + | |
| + | #define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. " |
| + | |
| + | |
| + | int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | uint64_t meta_off; |
| + | struct isw_meta *isw; |
| + | |
| + | dbg("probing at offset 0x%llx, size 0x%llx", |
| + | (unsigned long long) off, (unsigned long long) size); |
| + | |
| + | if (size < 0x10000) |
| + | return -1; |
| + | |
| + | meta_off = ((size / 0x200)-2) * 0x200; |
| + | isw = volume_id_get_buffer(id, off + meta_off, 0x200); |
| + | if (isw == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | memcpy(id->type_version, &isw->sig[sizeof(ISW_SIGNATURE)-1], 6); |
| + | id->type = "isw_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,59 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct jfs_super_block { |
| + | uint8_t magic[4]; |
| + | uint32_t version; |
| + | uint64_t size; |
| + | uint32_t bsize; |
| + | uint32_t dummy1; |
| + | uint32_t pbsize; |
| + | uint32_t dummy2[27]; |
| + | uint8_t uuid[16]; |
| + | uint8_t label[16]; |
| + | uint8_t loguuid[16]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define JFS_SUPERBLOCK_OFFSET 0x8000 |
| + | |
| + | int volume_id_probe_jfs(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct jfs_super_block *js; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | js = volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200); |
| + | if (js == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(js->magic, "JFS1", 4) != 0) |
| + | return -1; |
| + | |
| + | volume_id_set_label_raw(id, js->label, 16); |
| + | volume_id_set_label_string(id, js->label, 16); |
| + | volume_id_set_uuid(id, js->uuid, UUID_DCE); |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "jfs"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,79 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct mdp_super_block { |
| + | uint32_t md_magic; |
| + | uint32_t major_version; |
| + | uint32_t minor_version; |
| + | uint32_t patch_version; |
| + | uint32_t gvalid_words; |
| + | uint32_t set_uuid0; |
| + | uint32_t ctime; |
| + | uint32_t level; |
| + | uint32_t size; |
| + | uint32_t nr_disks; |
| + | uint32_t raid_disks; |
| + | uint32_t md_minor; |
| + | uint32_t not_persistent; |
| + | uint32_t set_uuid1; |
| + | uint32_t set_uuid2; |
| + | uint32_t set_uuid3; |
| + | } __attribute__((packed)); |
| + | |
| + | #define MD_RESERVED_BYTES 0x10000 |
| + | #define MD_MAGIC 0xa92b4efc |
| + | |
| + | int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | uint64_t sboff; |
| + | uint8_t uuid[16]; |
| + | struct mdp_super_block *mdp; |
| + | |
| + | dbg("probing at offset 0x%llx, size 0x%llx", |
| + | (unsigned long long) off, (unsigned long long) size); |
| + | |
| + | if (size < 0x10000) |
| + | return -1; |
| + | |
| + | sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES; |
| + | mdp = volume_id_get_buffer(id, off + sboff, 0x800); |
| + | if (mdp == NULL) |
| + | return -1; |
| + | |
| + | if (mdp->md_magic != cpu_to_le32(MD_MAGIC)) |
| + | return -1; |
| + | |
| + | memcpy(uuid, &mdp->set_uuid0, 4); |
| + | memcpy(&uuid[4], &mdp->set_uuid1, 12); |
| + | volume_id_set_uuid(id, uuid, UUID_DCE); |
| + | |
| + | snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u.%u", |
| + | le32_to_cpu(mdp->major_version), |
| + | le32_to_cpu(mdp->minor_version), |
| + | le32_to_cpu(mdp->patch_version)); |
| + | |
| + | dbg("found raid signature"); |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | id->type = "linux_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,73 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct swap_header_v1_2 { |
| + | uint8_t bootbits[1024]; |
| + | uint32_t version; |
| + | uint32_t last_page; |
| + | uint32_t nr_badpages; |
| + | uint8_t uuid[16]; |
| + | uint8_t volume_name[16]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define LARGEST_PAGESIZE 0x4000 |
| + | |
| + | int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct swap_header_v1_2 *sw; |
| + | const uint8_t *buf; |
| + | unsigned page; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | /* the swap signature is at the end of the PAGE_SIZE */ |
| + | for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) { |
| + | buf = volume_id_get_buffer(id, off + page-10, 10); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(buf, "SWAP-SPACE", 10) == 0) { |
| + | id->type_version[0] = '1'; |
| + | id->type_version[1] = '\0'; |
| + | goto found; |
| + | } |
| + | |
| + | if (memcmp(buf, "SWAPSPACE2", 10) == 0) { |
| + | sw = volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2)); |
| + | if (sw == NULL) |
| + | return -1; |
| + | id->type_version[0] = '2'; |
| + | id->type_version[1] = '\0'; |
| + | volume_id_set_label_raw(id, sw->volume_name, 16); |
| + | volume_id_set_label_string(id, sw->volume_name, 16); |
| + | volume_id_set_uuid(id, sw->uuid, UUID_DCE); |
| + | goto found; |
| + | } |
| + | } |
| + | return -1; |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_OTHER); |
| + | id->type = "swap"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,52 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct lsi_meta { |
| + | uint8_t sig[6]; |
| + | } __attribute__((packed)); |
| + | |
| + | #define LSI_SIGNATURE "$XIDE$" |
| + | |
| + | int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | uint64_t meta_off; |
| + | struct lsi_meta *lsi; |
| + | |
| + | dbg("probing at offset 0x%llx, size 0x%llx", |
| + | (unsigned long long) off, (unsigned long long) size); |
| + | |
| + | if (size < 0x10000) |
| + | return -1; |
| + | |
| + | meta_off = ((size / 0x200)-1) * 0x200; |
| + | lsi = volume_id_get_buffer(id, off + meta_off, 0x200); |
| + | if (lsi == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | id->type = "lsi_mega_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,76 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 W. Michael Petullo <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | #define SECTOR_SHIFT 9 |
| + | #define SECTOR_SIZE (1 << SECTOR_SHIFT) |
| + | |
| + | #define LUKS_CIPHERNAME_L 32 |
| + | #define LUKS_CIPHERMODE_L 32 |
| + | #define LUKS_HASHSPEC_L 32 |
| + | #define LUKS_DIGESTSIZE 20 |
| + | #define LUKS_SALTSIZE 32 |
| + | #define LUKS_NUMKEYS 8 |
| + | |
| + | static const uint8_t LUKS_MAGIC[] = { 'L','U','K','S', 0xba, 0xbe }; |
| + | #define LUKS_MAGIC_L 6 |
| + | #define LUKS_PHDR_SIZE (sizeof(struct luks_phdr)/SECTOR_SIZE+1) |
| + | #define UUID_STRING_L 40 |
| + | |
| + | struct luks_phdr { |
| + | uint8_t magic[LUKS_MAGIC_L]; |
| + | uint16_t version; |
| + | uint8_t cipherName[LUKS_CIPHERNAME_L]; |
| + | uint8_t cipherMode[LUKS_CIPHERMODE_L]; |
| + | uint8_t hashSpec[LUKS_HASHSPEC_L]; |
| + | uint32_t payloadOffset; |
| + | uint32_t keyBytes; |
| + | uint8_t mkDigest[LUKS_DIGESTSIZE]; |
| + | uint8_t mkDigestSalt[LUKS_SALTSIZE]; |
| + | uint32_t mkDigestIterations; |
| + | uint8_t uuid[UUID_STRING_L]; |
| + | struct { |
| + | uint32_t active; |
| + | uint32_t passwordIterations; |
| + | uint8_t passwordSalt[LUKS_SALTSIZE]; |
| + | uint32_t keyMaterialOffset; |
| + | uint32_t stripes; |
| + | } keyblock[LUKS_NUMKEYS]; |
| + | }; |
| + | |
| + | int volume_id_probe_luks(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct luks_phdr *header; |
| + | |
| + | header = volume_id_get_buffer(id, off, LUKS_PHDR_SIZE); |
| + | if (header == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(header->magic, LUKS_MAGIC, LUKS_MAGIC_L)) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_CRYPTO); |
| + | volume_id_set_uuid(id, header->uuid, UUID_DCE_STRING); |
| + | |
| + | id->type = "crypto_LUKS"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,91 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct lvm1_super_block { |
| + | uint8_t id[2]; |
| + | } __attribute__((packed)); |
| + | |
| + | struct lvm2_super_block { |
| + | uint8_t id[8]; |
| + | uint64_t sector_xl; |
| + | uint32_t crc_xl; |
| + | uint32_t offset_xl; |
| + | uint8_t type[8]; |
| + | } __attribute__((packed)); |
| + | |
| + | #define LVM1_SB_OFF 0x400 |
| + | #define LVM1_MAGIC "HM" |
| + | |
| + | int volume_id_probe_lvm1(struct volume_id *id, uint64_t off) |
| + | { |
| + | const uint8_t *buf; |
| + | struct lvm1_super_block *lvm; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | buf = volume_id_get_buffer(id, off + LVM1_SB_OFF, 0x800); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | lvm = (struct lvm1_super_block *) buf; |
| + | |
| + | if (memcmp(lvm->id, LVM1_MAGIC, 2) != 0) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | id->type = "LVM1_member"; |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | #define LVM2_LABEL_ID "LABELONE" |
| + | #define LVM2LABEL_SCAN_SECTORS 4 |
| + | |
| + | int volume_id_probe_lvm2(struct volume_id *id, uint64_t off) |
| + | { |
| + | const uint8_t *buf; |
| + | unsigned soff; |
| + | struct lvm2_super_block *lvm; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | buf = volume_id_get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | |
| + | for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) { |
| + | lvm = (struct lvm2_super_block *) &buf[soff]; |
| + | |
| + | if (memcmp(lvm->id, LVM2_LABEL_ID, 8) == 0) |
| + | goto found; |
| + | } |
| + | |
| + | return -1; |
| + | |
| + | found: |
| + | memcpy(id->type_version, lvm->type, 8); |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | id->type = "LVM2_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,125 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct mac_driver_desc { |
| + | uint8_t signature[2]; |
| + | uint16_t block_size; |
| + | uint32_t block_count; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct mac_partition { |
| + | uint8_t signature[2]; |
| + | uint16_t res1; |
| + | uint32_t map_count; |
| + | uint32_t start_block; |
| + | uint32_t block_count; |
| + | uint8_t name[32]; |
| + | uint8_t type[32]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | int volume_id_probe_mac_partition_map(struct volume_id *id, uint64_t off) |
| + | { |
| + | const uint8_t *buf; |
| + | struct mac_driver_desc *driver; |
| + | struct mac_partition *part; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | buf = volume_id_get_buffer(id, off, 0x200); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | part = (struct mac_partition *) buf; |
| + | if ((memcmp(part->signature, "PM", 2) == 0) && |
| + | (memcmp(part->type, "Apple_partition_map", 19) == 0)) { |
| + | /* linux creates an own subdevice for the map |
| + | * just return the type if the drive header is missing */ |
| + | volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE); |
| + | id->type = "mac_partition_map"; |
| + | return 0; |
| + | } |
| + | |
| + | driver = (struct mac_driver_desc *) buf; |
| + | if (memcmp(driver->signature, "ER", 2) == 0) { |
| + | /* we are on a main device, like a CD |
| + | * just try to probe the first partition from the map */ |
| + | unsigned bsize = be16_to_cpu(driver->block_size); |
| + | int part_count; |
| + | int i; |
| + | |
| + | /* get first entry of partition table */ |
| + | buf = volume_id_get_buffer(id, off + bsize, 0x200); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | part = (struct mac_partition *) buf; |
| + | if (memcmp(part->signature, "PM", 2) != 0) |
| + | return -1; |
| + | |
| + | part_count = be32_to_cpu(part->map_count); |
| + | dbg("expecting %d partition entries", part_count); |
| + | |
| + | if (id->partitions != NULL) |
| + | free(id->partitions); |
| + | id->partitions = |
| + | malloc(part_count * sizeof(struct volume_id_partition)); |
| + | if (id->partitions == NULL) |
| + | return -1; |
| + | memset(id->partitions, 0x00, sizeof(struct volume_id_partition)); |
| + | |
| + | id->partition_count = part_count; |
| + | |
| + | for (i = 0; i < part_count; i++) { |
| + | uint64_t poff; |
| + | uint64_t plen; |
| + | |
| + | buf = volume_id_get_buffer(id, off + ((i+1) * bsize), 0x200); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | part = (struct mac_partition *) buf; |
| + | if (memcmp(part->signature, "PM", 2) != 0) |
| + | return -1; |
| + | |
| + | poff = be32_to_cpu(part->start_block) * bsize; |
| + | plen = be32_to_cpu(part->block_count) * bsize; |
| + | dbg("found '%s' partition entry at 0x%llx, len 0x%llx", |
| + | part->type, (unsigned long long) poff, (unsigned long long) plen); |
| + | |
| + | id->partitions[i].off = poff; |
| + | id->partitions[i].len = plen; |
| + | |
| + | if (memcmp(part->type, "Apple_Free", 10) == 0) { |
| + | volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_UNUSED); |
| + | } else if (memcmp(part->type, "Apple_partition_map", 19) == 0) { |
| + | volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_PARTITIONTABLE); |
| + | } else { |
| + | volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_UNPROBED); |
| + | } |
| + | } |
| + | volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE); |
| + | id->type = "mac_partition_map"; |
| + | return 0; |
| + | } |
| + | |
| + | return -1; |
| + | } |
| @@ -0,0 +1,76 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct minix_super_block |
| + | { |
| + | uint16_t s_ninodes; |
| + | uint16_t s_nzones; |
| + | uint16_t s_imap_blocks; |
| + | uint16_t s_zmap_blocks; |
| + | uint16_t s_firstdatazone; |
| + | uint16_t s_log_zone_size; |
| + | uint32_t s_max_size; |
| + | uint16_t s_magic; |
| + | uint16_t s_state; |
| + | uint32_t s_zones; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define MINIX_SUPERBLOCK_OFFSET 0x400 |
| + | |
| + | int volume_id_probe_minix(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct minix_super_block *ms; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | ms = volume_id_get_buffer(id, off + MINIX_SUPERBLOCK_OFFSET, 0x200); |
| + | if (ms == NULL) |
| + | return -1; |
| + | |
| + | if (le16_to_cpu(ms->s_magic) == 0x137f) { |
| + | id->type_version[0] = '1'; |
| + | goto found; |
| + | } |
| + | |
| + | if (le16_to_cpu(ms->s_magic) == 0x1387) { |
| + | id->type_version[0] = '1'; |
| + | goto found; |
| + | } |
| + | |
| + | if (le16_to_cpu(ms->s_magic) == 0x2468) { |
| + | id->type_version[0] = '2'; |
| + | goto found; |
| + | } |
| + | |
| + | if (le16_to_cpu(ms->s_magic) == 0x2478) { |
| + | id->type_version[0] = '2'; |
| + | goto found; |
| + | } |
| + | |
| + | return -1; |
| + | |
| + | found: |
| + | id->type_version[1] = '\0'; |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "minix"; |
| + | return 0; |
| + | } |
| @@ -0,0 +1,196 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct msdos_partition_entry { |
| + | uint8_t boot_ind; |
| + | uint8_t head; |
| + | uint8_t sector; |
| + | uint8_t cyl; |
| + | uint8_t sys_ind; |
| + | uint8_t end_head; |
| + | uint8_t end_sector; |
| + | uint8_t end_cyl; |
| + | uint32_t start_sect; |
| + | uint32_t nr_sects; |
| + | } __attribute__((packed)); |
| + | |
| + | #define MSDOS_MAGIC "\x55\xaa" |
| + | #define MSDOS_PARTTABLE_OFFSET 0x1be |
| + | #define MSDOS_SIG_OFF 0x1fe |
| + | #define BSIZE 0x200 |
| + | #define DOS_EXTENDED_PARTITION 0x05 |
| + | #define LINUX_EXTENDED_PARTITION 0x85 |
| + | #define WIN98_EXTENDED_PARTITION 0x0f |
| + | #define LINUX_RAID_PARTITION 0xfd |
| + | #define is_extended(type) \ |
| + | (type == DOS_EXTENDED_PARTITION || \ |
| + | type == WIN98_EXTENDED_PARTITION || \ |
| + | type == LINUX_EXTENDED_PARTITION) |
| + | #define is_raid(type) \ |
| + | (type == LINUX_RAID_PARTITION) |
| + | |
| + | int volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t off) |
| + | { |
| + | const uint8_t *buf; |
| + | int i; |
| + | uint64_t poff; |
| + | uint64_t plen; |
| + | uint64_t extended = 0; |
| + | uint64_t current; |
| + | uint64_t next; |
| + | int limit; |
| + | int empty = 1; |
| + | struct msdos_partition_entry *part; |
| + | struct volume_id_partition *p; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | buf = volume_id_get_buffer(id, off, 0x200); |
| + | if (buf == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0) |
| + | return -1; |
| + | |
| + | /* check flags on all entries for a valid partition table */ |
| + | part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET]; |
| + | for (i = 0; i < 4; i++) { |
| + | if (part[i].boot_ind != 0 && |
| + | part[i].boot_ind != 0x80) |
| + | return -1; |
| + | |
| + | if (part[i].nr_sects != 0) |
| + | empty = 0; |
| + | } |
| + | if (empty == 1) |
| + | return -1; |
| + | |
| + | if (id->partitions != NULL) |
| + | free(id->partitions); |
| + | id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX * |
| + | sizeof(struct volume_id_partition)); |
| + | if (id->partitions == NULL) |
| + | return -1; |
| + | memset(id->partitions, 0x00, |
| + | VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition)); |
| + | |
| + | for (i = 0; i < 4; i++) { |
| + | poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE; |
| + | plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE; |
| + | |
| + | if (plen == 0) |
| + | continue; |
| + | |
| + | p = &id->partitions[i]; |
| + | |
| + | p->partition_type_raw = part[i].sys_ind; |
| + | |
| + | if (is_extended(part[i].sys_ind)) { |
| + | dbg("found extended partition at 0x%llx", (unsigned long long) poff); |
| + | volume_id_set_usage_part(p, VOLUME_ID_PARTITIONTABLE); |
| + | p->type = "msdos_extended_partition"; |
| + | if (extended == 0) |
| + | extended = off + poff; |
| + | } else { |
| + | dbg("found 0x%x data partition at 0x%llx, len 0x%llx", |
| + | part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen); |
| + | |
| + | if (is_raid(part[i].sys_ind)) |
| + | volume_id_set_usage_part(p, VOLUME_ID_RAID); |
| + | else |
| + | volume_id_set_usage_part(p, VOLUME_ID_UNPROBED); |
| + | } |
| + | |
| + | p->off = off + poff; |
| + | p->len = plen; |
| + | id->partition_count = i+1; |
| + | } |
| + | |
| + | next = extended; |
| + | current = extended; |
| + | limit = 50; |
| + | |
| + | /* follow extended partition chain and add data partitions */ |
| + | while (next != 0) { |
| + | if (limit-- == 0) { |
| + | dbg("extended chain limit reached"); |
| + | break; |
| + | } |
| + | |
| + | buf = volume_id_get_buffer(id, current, 0x200); |
| + | if (buf == NULL) |
| + | break; |
| + | |
| + | part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET]; |
| + | |
| + | if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0) |
| + | break; |
| + | |
| + | next = 0; |
| + | |
| + | for (i = 0; i < 4; i++) { |
| + | poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE; |
| + | plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE; |
| + | |
| + | if (plen == 0) |
| + | continue; |
| + | |
| + | if (is_extended(part[i].sys_ind)) { |
| + | dbg("found extended partition at 0x%llx", (unsigned long long) poff); |
| + | if (next == 0) |
| + | next = extended + poff; |
| + | } else { |
| + | dbg("found 0x%x data partition at 0x%llx, len 0x%llx", |
| + | part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen); |
| + | |
| + | /* we always start at the 5th entry */ |
| + | while (id->partition_count < 4) |
| + | volume_id_set_usage_part(&id->partitions[id->partition_count++], VOLUME_ID_UNUSED); |
| + | |
| + | p = &id->partitions[id->partition_count]; |
| + | |
| + | if (is_raid(part[i].sys_ind)) |
| + | volume_id_set_usage_part(p, VOLUME_ID_RAID); |
| + | else |
| + | volume_id_set_usage_part(p, VOLUME_ID_UNPROBED); |
| + | |
| + | p->off = current + poff; |
| + | p->len = plen; |
| + | id->partition_count++; |
| + | |
| + | p->partition_type_raw = part[i].sys_ind; |
| + | |
| + | if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) { |
| + | dbg("too many partitions"); |
| + | next = 0; |
| + | } |
| + | } |
| + | } |
| + | |
| + | current = next; |
| + | } |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE); |
| + | id->type = "msdos_partition_table"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,193 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct ntfs_super_block { |
| + | uint8_t jump[3]; |
| + | uint8_t oem_id[8]; |
| + | uint16_t bytes_per_sector; |
| + | uint8_t sectors_per_cluster; |
| + | uint16_t reserved_sectors; |
| + | uint8_t fats; |
| + | uint16_t root_entries; |
| + | uint16_t sectors; |
| + | uint8_t media_type; |
| + | uint16_t sectors_per_fat; |
| + | uint16_t sectors_per_track; |
| + | uint16_t heads; |
| + | uint32_t hidden_sectors; |
| + | uint32_t large_sectors; |
| + | uint16_t unused[2]; |
| + | uint64_t number_of_sectors; |
| + | uint64_t mft_cluster_location; |
| + | uint64_t mft_mirror_cluster_location; |
| + | int8_t cluster_per_mft_record; |
| + | uint8_t reserved1[3]; |
| + | int8_t cluster_per_index_record; |
| + | uint8_t reserved2[3]; |
| + | uint8_t volume_serial[8]; |
| + | uint16_t checksum; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct master_file_table_record { |
| + | uint8_t magic[4]; |
| + | uint16_t usa_ofs; |
| + | uint16_t usa_count; |
| + | uint64_t lsn; |
| + | uint16_t sequence_number; |
| + | uint16_t link_count; |
| + | uint16_t attrs_offset; |
| + | uint16_t flags; |
| + | uint32_t bytes_in_use; |
| + | uint32_t bytes_allocated; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct file_attribute { |
| + | uint32_t type; |
| + | uint32_t len; |
| + | uint8_t non_resident; |
| + | uint8_t name_len; |
| + | uint16_t name_offset; |
| + | uint16_t flags; |
| + | uint16_t instance; |
| + | uint32_t value_len; |
| + | uint16_t value_offset; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct volume_info { |
| + | uint64_t reserved; |
| + | uint8_t major_ver; |
| + | uint8_t minor_ver; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define MFT_RECORD_VOLUME 3 |
| + | #define MFT_RECORD_ATTR_VOLUME_NAME 0x60 |
| + | #define MFT_RECORD_ATTR_VOLUME_INFO 0x70 |
| + | #define MFT_RECORD_ATTR_OBJECT_ID 0x40 |
| + | #define MFT_RECORD_ATTR_END 0xffffffffu |
| + | |
| + | int volume_id_probe_ntfs(struct volume_id *id, uint64_t off) |
| + | { |
| + | unsigned sector_size; |
| + | unsigned cluster_size; |
| + | uint64_t mft_cluster; |
| + | uint64_t mft_off; |
| + | unsigned mft_record_size; |
| + | unsigned attr_type; |
| + | unsigned attr_off; |
| + | unsigned attr_len; |
| + | unsigned val_off; |
| + | unsigned val_len; |
| + | struct master_file_table_record *mftr; |
| + | struct ntfs_super_block *ns; |
| + | const uint8_t *buf; |
| + | const uint8_t *val; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | ns = volume_id_get_buffer(id, off, 0x200); |
| + | if (ns == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(ns->oem_id, "NTFS", 4) != 0) |
| + | return -1; |
| + | |
| + | volume_id_set_uuid(id, ns->volume_serial, UUID_NTFS); |
| + | |
| + | sector_size = le16_to_cpu(ns->bytes_per_sector); |
| + | cluster_size = ns->sectors_per_cluster * sector_size; |
| + | mft_cluster = le64_to_cpu(ns->mft_cluster_location); |
| + | mft_off = mft_cluster * cluster_size; |
| + | |
| + | if (ns->cluster_per_mft_record < 0) |
| + | /* size = -log2(mft_record_size); normally 1024 Bytes */ |
| + | mft_record_size = 1 << -ns->cluster_per_mft_record; |
| + | else |
| + | mft_record_size = ns->cluster_per_mft_record * cluster_size; |
| + | |
| + | dbg("sectorsize 0x%x", sector_size); |
| + | dbg("clustersize 0x%x", cluster_size); |
| + | dbg("mftcluster %llu", (unsigned long long) mft_cluster); |
| + | dbg("mftoffset 0x%llx", (unsigned long long) mft_off); |
| + | dbg("cluster per mft_record %i", ns->cluster_per_mft_record); |
| + | dbg("mft record size %i", mft_record_size); |
| + | |
| + | buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size), |
| + | mft_record_size); |
| + | if (buf == NULL) |
| + | goto found; |
| + | |
| + | mftr = (struct master_file_table_record*) buf; |
| + | |
| + | dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]); |
| + | if (memcmp(mftr->magic, "FILE", 4) != 0) |
| + | goto found; |
| + | |
| + | attr_off = le16_to_cpu(mftr->attrs_offset); |
| + | dbg("file $Volume's attributes are at offset %i", attr_off); |
| + | |
| + | while (1) { |
| + | struct file_attribute *attr; |
| + | |
| + | attr = (struct file_attribute*) &buf[attr_off]; |
| + | attr_type = le32_to_cpu(attr->type); |
| + | attr_len = le16_to_cpu(attr->len); |
| + | val_off = le16_to_cpu(attr->value_offset); |
| + | val_len = le32_to_cpu(attr->value_len); |
| + | attr_off += attr_len; |
| + | |
| + | if (attr_len == 0) |
| + | break; |
| + | |
| + | if (attr_off >= mft_record_size) |
| + | break; |
| + | |
| + | if (attr_type == MFT_RECORD_ATTR_END) |
| + | break; |
| + | |
| + | dbg("found attribute type 0x%x, len %i, at offset %i", |
| + | attr_type, attr_len, attr_off); |
| + | |
| + | if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) { |
| + | struct volume_info *info; |
| + | dbg("found info, len %i", val_len); |
| + | info = (struct volume_info*) (((uint8_t *) attr) + val_off); |
| + | snprintf(id->type_version, sizeof(id->type_version)-1, |
| + | "%u.%u", info->major_ver, info->minor_ver); |
| + | } |
| + | |
| + | if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { |
| + | dbg("found label, len %i", val_len); |
| + | if (val_len > VOLUME_ID_LABEL_SIZE) |
| + | val_len = VOLUME_ID_LABEL_SIZE; |
| + | |
| + | val = ((uint8_t *) attr) + val_off; |
| + | volume_id_set_label_raw(id, val, val_len); |
| + | volume_id_set_label_unicode16(id, val, LE, val_len); |
| + | } |
| + | } |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "ntfs"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,56 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct nvidia_meta { |
| + | uint8_t vendor[8]; |
| + | uint32_t size; |
| + | uint32_t chksum; |
| + | uint16_t version; |
| + | } __attribute__((packed)); |
| + | |
| + | #define NVIDIA_SIGNATURE "NVIDIA" |
| + | |
| + | int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | uint64_t meta_off; |
| + | struct nvidia_meta *nv; |
| + | |
| + | dbg("probing at offset 0x%llx, size 0x%llx", |
| + | (unsigned long long) off, (unsigned long long) size); |
| + | |
| + | if (size < 0x10000) |
| + | return -1; |
| + | |
| + | meta_off = ((size / 0x200)-2) * 0x200; |
| + | nv = volume_id_get_buffer(id, off + meta_off, 0x200); |
| + | if (nv == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | snprintf(id->type_version, sizeof(id->type_version)-1, "%u", le16_to_cpu(nv->version)); |
| + | id->type = "nvidia_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,105 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) Andre Masella <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | /* All these values are taken from ocfs2-tools's ocfs2_fs.h */ |
| + | #define OCFS2_VOL_UUID_LEN 16 |
| + | #define OCFS2_MAX_VOL_LABEL_LEN 64 |
| + | #define OCFS2_SUPERBLOCK_OFFSET 0x2000 |
| + | |
| + | |
| + | /* This is the superblock. The OCFS2 header files have structs in structs. |
| + | This is one has been simplified since we only care about the superblock. |
| + | */ |
| + | |
| + | struct ocfs2_super_block { |
| + | uint8_t i_signature[8]; /* Signature for validation */ |
| + | uint32_t i_generation; /* Generation number */ |
| + | int16_t i_suballoc_slot; /* Slot suballocator this inode belongs to */ |
| + | uint16_t i_suballoc_bit; /* Bit offset in suballocator block group */ |
| + | uint32_t i_reserved0; |
| + | uint32_t i_clusters; /* Cluster count */ |
| + | uint32_t i_uid; /* Owner UID */ |
| + | uint32_t i_gid; /* Owning GID */ |
| + | uint64_t i_size; /* Size in bytes */ |
| + | uint16_t i_mode; /* File mode */ |
| + | uint16_t i_links_count; /* Links count */ |
| + | uint32_t i_flags; /* File flags */ |
| + | uint64_t i_atime; /* Access time */ |
| + | uint64_t i_ctime; /* Creation time */ |
| + | uint64_t i_mtime; /* Modification time */ |
| + | uint64_t i_dtime; /* Deletion time */ |
| + | uint64_t i_blkno; /* Offset on disk, in blocks */ |
| + | uint64_t i_last_eb_blk; /* Pointer to last extent block */ |
| + | uint32_t i_fs_generation; /* Generation per fs-instance */ |
| + | uint32_t i_atime_nsec; |
| + | uint32_t i_ctime_nsec; |
| + | uint32_t i_mtime_nsec; |
| + | uint64_t i_reserved1[9]; |
| + | uint64_t i_pad1; /* Generic way to refer to this 64bit union */ |
| + | /* Normally there is a union of the different block types, but we only care about the superblock. */ |
| + | uint16_t s_major_rev_level; |
| + | uint16_t s_minor_rev_level; |
| + | uint16_t s_mnt_count; |
| + | int16_t s_max_mnt_count; |
| + | uint16_t s_state; /* File system state */ |
| + | uint16_t s_errors; /* Behaviour when detecting errors */ |
| + | uint32_t s_checkinterval; /* Max time between checks */ |
| + | uint64_t s_lastcheck; /* Time of last check */ |
| + | uint32_t s_creator_os; /* OS */ |
| + | uint32_t s_feature_compat; /* Compatible feature set */ |
| + | uint32_t s_feature_incompat; /* Incompatible feature set */ |
| + | uint32_t s_feature_ro_compat; /* Readonly-compatible feature set */ |
| + | uint64_t s_root_blkno; /* Offset, in blocks, of root directory dinode */ |
| + | uint64_t s_system_dir_blkno; /* Offset, in blocks, of system directory dinode */ |
| + | uint32_t s_blocksize_bits; /* Blocksize for this fs */ |
| + | uint32_t s_clustersize_bits; /* Clustersize for this fs */ |
| + | uint16_t s_max_slots; /* Max number of simultaneous mounts before tunefs required */ |
| + | uint16_t s_reserved1; |
| + | uint32_t s_reserved2; |
| + | uint64_t s_first_cluster_group; /* Block offset of 1st cluster group header */ |
| + | uint8_t s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ |
| + | uint8_t s_uuid[OCFS2_VOL_UUID_LEN]; /* 128-bit uuid */ |
| + | } __attribute__((__packed__)); |
| + | |
| + | int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct ocfs2_super_block *os; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | os = volume_id_get_buffer(id, off + OCFS2_SUPERBLOCK_OFFSET, 0x200); |
| + | if (os == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(os->i_signature, "OCFSV2", 6) != 0) { |
| + | return -1; |
| + | } |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | volume_id_set_label_raw(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ? |
| + | OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE); |
| + | volume_id_set_label_string(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ? |
| + | OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE); |
| + | volume_id_set_uuid(id, os->s_uuid, UUID_DCE); |
| + | id->type = "ocfs2"; |
| + | return 0; |
| + | } |
| @@ -0,0 +1,63 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct promise_meta { |
| + | uint8_t sig[24]; |
| + | } __attribute__((packed)); |
| + | |
| + | #define PDC_CONFIG_OFF 0x1200 |
| + | #define PDC_SIGNATURE "Promise Technology, Inc." |
| + | |
| + | int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | static const unsigned short sectors[] = { |
| + | 63, 255, 256, 16, 399 |
| + | }; |
| + | |
| + | struct promise_meta *pdc; |
| + | unsigned i; |
| + | |
| + | dbg("probing at offset 0x%llx, size 0x%llx", |
| + | (unsigned long long) off, (unsigned long long) size); |
| + | |
| + | if (size < 0x40000) |
| + | return -1; |
| + | |
| + | for (i = 0; i < ARRAY_SIZE(sectors); i++) { |
| + | uint64_t meta_off; |
| + | |
| + | meta_off = ((size / 0x200) - sectors[i]) * 0x200; |
| + | pdc = volume_id_get_buffer(id, off + meta_off, 0x200); |
| + | if (pdc == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(pdc->sig, PDC_SIGNATURE, sizeof(PDC_SIGNATURE)-1) == 0) |
| + | goto found; |
| + | } |
| + | return -1; |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | id->type = "promise_fasttrack_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,105 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * Copyright (C) 2005 Tobias Klauser <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct reiserfs_super_block { |
| + | uint32_t blocks_count; |
| + | uint32_t free_blocks; |
| + | uint32_t root_block; |
| + | uint32_t journal_block; |
| + | uint32_t journal_dev; |
| + | uint32_t orig_journal_size; |
| + | uint32_t dummy2[5]; |
| + | uint16_t blocksize; |
| + | uint16_t dummy3[3]; |
| + | uint8_t magic[12]; |
| + | uint32_t dummy4[5]; |
| + | uint8_t uuid[16]; |
| + | uint8_t label[16]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct reiser4_super_block { |
| + | uint8_t magic[16]; |
| + | uint16_t dummy[2]; |
| + | uint8_t uuid[16]; |
| + | uint8_t label[16]; |
| + | uint64_t dummy2; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define REISERFS1_SUPERBLOCK_OFFSET 0x2000 |
| + | #define REISERFS_SUPERBLOCK_OFFSET 0x10000 |
| + | |
| + | int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct reiserfs_super_block *rs; |
| + | struct reiser4_super_block *rs4; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | rs = volume_id_get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200); |
| + | if (rs == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(rs->magic, "ReIsErFs", 8) == 0) { |
| + | strcpy(id->type_version, "3.5"); |
| + | goto found; |
| + | } |
| + | if (memcmp(rs->magic, "ReIsEr2Fs", 9) == 0) { |
| + | strcpy(id->type_version, "3.6"); |
| + | goto found_label; |
| + | } |
| + | if (memcmp(rs->magic, "ReIsEr3Fs", 9) == 0) { |
| + | strcpy(id->type_version, "JR"); |
| + | goto found_label; |
| + | } |
| + | |
| + | rs4 = (struct reiser4_super_block *) rs; |
| + | if (memcmp(rs4->magic, "ReIsEr4", 7) == 0) { |
| + | strcpy(id->type_version, "4"); |
| + | volume_id_set_label_raw(id, rs4->label, 16); |
| + | volume_id_set_label_string(id, rs4->label, 16); |
| + | volume_id_set_uuid(id, rs4->uuid, UUID_DCE); |
| + | goto found; |
| + | } |
| + | |
| + | rs = volume_id_get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200); |
| + | if (rs == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(rs->magic, "ReIsErFs", 8) == 0) { |
| + | strcpy(id->type_version, "3.5"); |
| + | goto found; |
| + | } |
| + | |
| + | return -1; |
| + | |
| + | found_label: |
| + | volume_id_set_label_raw(id, rs->label, 16); |
| + | volume_id_set_label_string(id, rs->label, 16); |
| + | volume_id_set_uuid(id, rs->uuid, UUID_DCE); |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "reiserfs"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,54 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct romfs_super { |
| + | uint8_t magic[8]; |
| + | uint32_t size; |
| + | uint32_t checksum; |
| + | uint8_t name[0]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | int volume_id_probe_romfs(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct romfs_super *rfs; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | rfs = volume_id_get_buffer(id, off, 0x200); |
| + | if (rfs == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(rfs->magic, "-rom1fs-", 4) == 0) { |
| + | size_t len = strlen((char *)rfs->name); |
| + | |
| + | if (len) { |
| + | volume_id_set_label_raw(id, rfs->name, len); |
| + | volume_id_set_label_string(id, rfs->name, len); |
| + | } |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "romfs"; |
| + | return 0; |
| + | } |
| + | |
| + | return -1; |
| + | } |
| @@ -0,0 +1,69 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct silicon_meta { |
| + | uint8_t unknown0[0x2E]; |
| + | uint8_t ascii_version[0x36 - 0x2E]; |
| + | uint8_t diskname[0x56 - 0x36]; |
| + | uint8_t unknown1[0x60 - 0x56]; |
| + | uint32_t magic; |
| + | uint32_t unknown1a[0x6C - 0x64]; |
| + | uint32_t array_sectors_low; |
| + | uint32_t array_sectors_high; |
| + | uint8_t unknown2[0x78 - 0x74]; |
| + | uint32_t thisdisk_sectors; |
| + | uint8_t unknown3[0x100 - 0x7C]; |
| + | uint8_t unknown4[0x104 - 0x100]; |
| + | uint16_t product_id; |
| + | uint16_t vendor_id; |
| + | uint16_t minor_ver; |
| + | uint16_t major_ver; |
| + | } __attribute__((packed)); |
| + | |
| + | #define SILICON_MAGIC 0x2F000000 |
| + | |
| + | int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | uint64_t meta_off; |
| + | struct silicon_meta *sil; |
| + | |
| + | dbg("probing at offset 0x%llx, size 0x%llx", |
| + | (unsigned long long) off, (unsigned long long) size); |
| + | |
| + | if (size < 0x10000) |
| + | return -1; |
| + | |
| + | meta_off = ((size / 0x200)-1) * 0x200; |
| + | sil = volume_id_get_buffer(id, off + meta_off, 0x200); |
| + | if (sil == NULL) |
| + | return -1; |
| + | |
| + | if (sil->magic != cpu_to_le32(SILICON_MAGIC)) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u", |
| + | le16_to_cpu(sil->major_ver), le16_to_cpu(sil->minor_ver)); |
| + | id->type = "silicon_medley_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,125 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | #define SYSV_NICINOD 100 |
| + | #define SYSV_NICFREE 50 |
| + | |
| + | struct sysv_super |
| + | { |
| + | uint16_t s_isize; |
| + | uint16_t s_pad0; |
| + | uint32_t s_fsize; |
| + | uint16_t s_nfree; |
| + | uint16_t s_pad1; |
| + | uint32_t s_free[SYSV_NICFREE]; |
| + | uint16_t s_ninode; |
| + | uint16_t s_pad2; |
| + | uint16_t s_inode[SYSV_NICINOD]; |
| + | uint8_t s_flock; |
| + | uint8_t s_ilock; |
| + | uint8_t s_fmod; |
| + | uint8_t s_ronly; |
| + | uint32_t s_time; |
| + | uint16_t s_dinfo[4]; |
| + | uint32_t s_tfree; |
| + | uint16_t s_tinode; |
| + | uint16_t s_pad3; |
| + | uint8_t s_fname[6]; |
| + | uint8_t s_fpack[6]; |
| + | uint32_t s_fill[12]; |
| + | uint32_t s_state; |
| + | uint32_t s_magic; |
| + | uint32_t s_type; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define XENIX_NICINOD 100 |
| + | #define XENIX_NICFREE 100 |
| + | |
| + | struct xenix_super { |
| + | uint16_t s_isize; |
| + | uint32_t s_fsize; |
| + | uint16_t s_nfree; |
| + | uint32_t s_free[XENIX_NICFREE]; |
| + | uint16_t s_ninode; |
| + | uint16_t s_inode[XENIX_NICINOD]; |
| + | uint8_t s_flock; |
| + | uint8_t s_ilock; |
| + | uint8_t s_fmod; |
| + | uint8_t s_ronly; |
| + | uint32_t s_time; |
| + | uint32_t s_tfree; |
| + | uint16_t s_tinode; |
| + | uint16_t s_dinfo[4]; |
| + | uint8_t s_fname[6]; |
| + | uint8_t s_fpack[6]; |
| + | uint8_t s_clean; |
| + | uint8_t s_fill[371]; |
| + | uint32_t s_magic; |
| + | uint32_t s_type; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define SYSV_SUPERBLOCK_BLOCK 0x01 |
| + | #define SYSV_MAGIC 0xfd187e20 |
| + | #define XENIX_SUPERBLOCK_BLOCK 0x18 |
| + | #define XENIX_MAGIC 0x2b5544 |
| + | #define SYSV_MAX_BLOCKSIZE 0x800 |
| + | |
| + | int volume_id_probe_sysv(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct sysv_super *vs; |
| + | struct xenix_super *xs; |
| + | unsigned boff; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) { |
| + | vs = volume_id_get_buffer(id, off + (boff * SYSV_SUPERBLOCK_BLOCK), 0x200); |
| + | if (vs == NULL) |
| + | return -1; |
| + | |
| + | if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) { |
| + | volume_id_set_label_raw(id, vs->s_fname, 6); |
| + | volume_id_set_label_string(id, vs->s_fname, 6); |
| + | id->type = "sysv"; |
| + | goto found; |
| + | } |
| + | } |
| + | |
| + | for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) { |
| + | xs = volume_id_get_buffer(id, off + (boff + XENIX_SUPERBLOCK_BLOCK), 0x200); |
| + | if (xs == NULL) |
| + | return -1; |
| + | |
| + | if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) { |
| + | volume_id_set_label_raw(id, xs->s_fname, 6); |
| + | volume_id_set_label_string(id, xs->s_fname, 6); |
| + | id->type = "xenix"; |
| + | goto found; |
| + | } |
| + | } |
| + | |
| + | return -1; |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | return 0; |
| + | } |
| @@ -0,0 +1,172 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct volume_descriptor { |
| + | struct descriptor_tag { |
| + | uint16_t id; |
| + | uint16_t version; |
| + | uint8_t checksum; |
| + | uint8_t reserved; |
| + | uint16_t serial; |
| + | uint16_t crc; |
| + | uint16_t crc_len; |
| + | uint32_t location; |
| + | } __attribute__((__packed__)) tag; |
| + | union { |
| + | struct anchor_descriptor { |
| + | uint32_t length; |
| + | uint32_t location; |
| + | } __attribute__((__packed__)) anchor; |
| + | struct primary_descriptor { |
| + | uint32_t seq_num; |
| + | uint32_t desc_num; |
| + | struct dstring { |
| + | uint8_t clen; |
| + | uint8_t c[31]; |
| + | } __attribute__((__packed__)) ident; |
| + | } __attribute__((__packed__)) primary; |
| + | } __attribute__((__packed__)) type; |
| + | } __attribute__((__packed__)); |
| + | |
| + | struct volume_structure_descriptor { |
| + | uint8_t type; |
| + | uint8_t id[5]; |
| + | uint8_t version; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define UDF_VSD_OFFSET 0x8000 |
| + | |
| + | int volume_id_probe_udf(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct volume_descriptor *vd; |
| + | struct volume_structure_descriptor *vsd; |
| + | unsigned bs; |
| + | unsigned b; |
| + | unsigned type; |
| + | unsigned count; |
| + | unsigned loc; |
| + | unsigned clen; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200); |
| + | if (vsd == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(vsd->id, "NSR02", 5) == 0) |
| + | goto blocksize; |
| + | if (memcmp(vsd->id, "NSR03", 5) == 0) |
| + | goto blocksize; |
| + | if (memcmp(vsd->id, "BEA01", 5) == 0) |
| + | goto blocksize; |
| + | if (memcmp(vsd->id, "BOOT2", 5) == 0) |
| + | goto blocksize; |
| + | if (memcmp(vsd->id, "CD001", 5) == 0) |
| + | goto blocksize; |
| + | if (memcmp(vsd->id, "CDW02", 5) == 0) |
| + | goto blocksize; |
| + | if (memcmp(vsd->id, "TEA03", 5) == 0) |
| + | goto blocksize; |
| + | return -1; |
| + | |
| + | blocksize: |
| + | /* search the next VSD to get the logical block size of the volume */ |
| + | for (bs = 0x800; bs < 0x8000; bs += 0x800) { |
| + | vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800); |
| + | if (vsd == NULL) |
| + | return -1; |
| + | dbg("test for blocksize: 0x%x", bs); |
| + | if (vsd->id[0] != '\0') |
| + | goto nsr; |
| + | } |
| + | return -1; |
| + | |
| + | nsr: |
| + | /* search the list of VSDs for a NSR descriptor */ |
| + | for (b = 0; b < 64; b++) { |
| + | vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800); |
| + | if (vsd == NULL) |
| + | return -1; |
| + | |
| + | dbg("vsd: %c%c%c%c%c", |
| + | vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]); |
| + | |
| + | if (vsd->id[0] == '\0') |
| + | return -1; |
| + | if (memcmp(vsd->id, "NSR02", 5) == 0) |
| + | goto anchor; |
| + | if (memcmp(vsd->id, "NSR03", 5) == 0) |
| + | goto anchor; |
| + | } |
| + | return -1; |
| + | |
| + | anchor: |
| + | /* read anchor volume descriptor */ |
| + | vd = volume_id_get_buffer(id, off + (256 * bs), 0x200); |
| + | if (vd == NULL) |
| + | return -1; |
| + | |
| + | type = le16_to_cpu(vd->tag.id); |
| + | if (type != 2) /* TAG_ID_AVDP */ |
| + | goto found; |
| + | |
| + | /* get desriptor list address and block count */ |
| + | count = le32_to_cpu(vd->type.anchor.length) / bs; |
| + | loc = le32_to_cpu(vd->type.anchor.location); |
| + | dbg("0x%x descriptors starting at logical secor 0x%x", count, loc); |
| + | |
| + | /* pick the primary descriptor from the list */ |
| + | for (b = 0; b < count; b++) { |
| + | vd = volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200); |
| + | if (vd == NULL) |
| + | return -1; |
| + | |
| + | type = le16_to_cpu(vd->tag.id); |
| + | dbg("descriptor type %i", type); |
| + | |
| + | /* check validity */ |
| + | if (type == 0) |
| + | goto found; |
| + | if (le32_to_cpu(vd->tag.location) != loc + b) |
| + | goto found; |
| + | |
| + | if (type == 1) /* TAG_ID_PVD */ |
| + | goto pvd; |
| + | } |
| + | goto found; |
| + | |
| + | pvd: |
| + | volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32); |
| + | |
| + | clen = vd->type.primary.ident.clen; |
| + | dbg("label string charsize=%i bit", clen); |
| + | if (clen == 8) |
| + | volume_id_set_label_string(id, vd->type.primary.ident.c, 31); |
| + | else if (clen == 16) |
| + | volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE, 31); |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "udf"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,206 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct ufs_super_block { |
| + | uint32_t fs_link; |
| + | uint32_t fs_rlink; |
| + | uint32_t fs_sblkno; |
| + | uint32_t fs_cblkno; |
| + | uint32_t fs_iblkno; |
| + | uint32_t fs_dblkno; |
| + | uint32_t fs_cgoffset; |
| + | uint32_t fs_cgmask; |
| + | uint32_t fs_time; |
| + | uint32_t fs_size; |
| + | uint32_t fs_dsize; |
| + | uint32_t fs_ncg; |
| + | uint32_t fs_bsize; |
| + | uint32_t fs_fsize; |
| + | uint32_t fs_frag; |
| + | uint32_t fs_minfree; |
| + | uint32_t fs_rotdelay; |
| + | uint32_t fs_rps; |
| + | uint32_t fs_bmask; |
| + | uint32_t fs_fmask; |
| + | uint32_t fs_bshift; |
| + | uint32_t fs_fshift; |
| + | uint32_t fs_maxcontig; |
| + | uint32_t fs_maxbpg; |
| + | uint32_t fs_fragshift; |
| + | uint32_t fs_fsbtodb; |
| + | uint32_t fs_sbsize; |
| + | uint32_t fs_csmask; |
| + | uint32_t fs_csshift; |
| + | uint32_t fs_nindir; |
| + | uint32_t fs_inopb; |
| + | uint32_t fs_nspf; |
| + | uint32_t fs_optim; |
| + | uint32_t fs_npsect_state; |
| + | uint32_t fs_interleave; |
| + | uint32_t fs_trackskew; |
| + | uint32_t fs_id[2]; |
| + | uint32_t fs_csaddr; |
| + | uint32_t fs_cssize; |
| + | uint32_t fs_cgsize; |
| + | uint32_t fs_ntrak; |
| + | uint32_t fs_nsect; |
| + | uint32_t fs_spc; |
| + | uint32_t fs_ncyl; |
| + | uint32_t fs_cpg; |
| + | uint32_t fs_ipg; |
| + | uint32_t fs_fpg; |
| + | struct ufs_csum { |
| + | uint32_t cs_ndir; |
| + | uint32_t cs_nbfree; |
| + | uint32_t cs_nifree; |
| + | uint32_t cs_nffree; |
| + | } __attribute__((__packed__)) fs_cstotal; |
| + | int8_t fs_fmod; |
| + | int8_t fs_clean; |
| + | int8_t fs_ronly; |
| + | int8_t fs_flags; |
| + | union { |
| + | struct { |
| + | int8_t fs_fsmnt[512]; |
| + | uint32_t fs_cgrotor; |
| + | uint32_t fs_csp[31]; |
| + | uint32_t fs_maxcluster; |
| + | uint32_t fs_cpc; |
| + | uint16_t fs_opostbl[16][8]; |
| + | } __attribute__((__packed__)) fs_u1; |
| + | struct { |
| + | int8_t fs_fsmnt[468]; |
| + | uint8_t fs_volname[32]; |
| + | uint64_t fs_swuid; |
| + | int32_t fs_pad; |
| + | uint32_t fs_cgrotor; |
| + | uint32_t fs_ocsp[28]; |
| + | uint32_t fs_contigdirs; |
| + | uint32_t fs_csp; |
| + | uint32_t fs_maxcluster; |
| + | uint32_t fs_active; |
| + | int32_t fs_old_cpc; |
| + | int32_t fs_maxbsize; |
| + | int64_t fs_sparecon64[17]; |
| + | int64_t fs_sblockloc; |
| + | struct ufs2_csum_total { |
| + | uint64_t cs_ndir; |
| + | uint64_t cs_nbfree; |
| + | uint64_t cs_nifree; |
| + | uint64_t cs_nffree; |
| + | uint64_t cs_numclusters; |
| + | uint64_t cs_spare[3]; |
| + | } __attribute__((__packed__)) fs_cstotal; |
| + | struct ufs_timeval { |
| + | int32_t tv_sec; |
| + | int32_t tv_usec; |
| + | } __attribute__((__packed__)) fs_time; |
| + | int64_t fs_size; |
| + | int64_t fs_dsize; |
| + | uint64_t fs_csaddr; |
| + | int64_t fs_pendingblocks; |
| + | int32_t fs_pendinginodes; |
| + | } __attribute__((__packed__)) fs_u2; |
| + | } fs_u11; |
| + | union { |
| + | struct { |
| + | int32_t fs_sparecon[53]; |
| + | int32_t fs_reclaim; |
| + | int32_t fs_sparecon2[1]; |
| + | int32_t fs_state; |
| + | uint32_t fs_qbmask[2]; |
| + | uint32_t fs_qfmask[2]; |
| + | } __attribute__((__packed__)) fs_sun; |
| + | struct { |
| + | int32_t fs_sparecon[53]; |
| + | int32_t fs_reclaim; |
| + | int32_t fs_sparecon2[1]; |
| + | uint32_t fs_npsect; |
| + | uint32_t fs_qbmask[2]; |
| + | uint32_t fs_qfmask[2]; |
| + | } __attribute__((__packed__)) fs_sunx86; |
| + | struct { |
| + | int32_t fs_sparecon[50]; |
| + | int32_t fs_contigsumsize; |
| + | int32_t fs_maxsymlinklen; |
| + | int32_t fs_inodefmt; |
| + | uint32_t fs_maxfilesize[2]; |
| + | uint32_t fs_qbmask[2]; |
| + | uint32_t fs_qfmask[2]; |
| + | int32_t fs_state; |
| + | } __attribute__((__packed__)) fs_44; |
| + | } fs_u2; |
| + | int32_t fs_postblformat; |
| + | int32_t fs_nrpos; |
| + | int32_t fs_postbloff; |
| + | int32_t fs_rotbloff; |
| + | uint32_t fs_magic; |
| + | uint8_t fs_space[1]; |
| + | } __attribute__((__packed__)); |
| + | |
| + | #define UFS_MAGIC 0x00011954 |
| + | #define UFS2_MAGIC 0x19540119 |
| + | #define UFS_MAGIC_FEA 0x00195612 |
| + | #define UFS_MAGIC_LFN 0x00095014 |
| + | |
| + | int volume_id_probe_ufs(struct volume_id *id, uint64_t off) |
| + | { |
| + | static const short offsets[] = { 0, 8, 64, 256 }; |
| + | |
| + | uint32_t magic; |
| + | int i; |
| + | struct ufs_super_block *ufs; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | for (i = 0; i < ARRAY_SIZE(offsets); i++) { |
| + | ufs = volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800); |
| + | if (ufs == NULL) |
| + | return -1; |
| + | |
| + | dbg("offset 0x%x", offsets[i] * 0x400); |
| + | magic = ufs->fs_magic; |
| + | if ((magic == cpu_to_be32(UFS_MAGIC)) |
| + | || (magic == cpu_to_be32(UFS2_MAGIC)) |
| + | || (magic == cpu_to_be32(UFS_MAGIC_FEA)) |
| + | || (magic == cpu_to_be32(UFS_MAGIC_LFN)) |
| + | ) { |
| + | dbg("magic 0x%08x(be)", magic); |
| + | goto found; |
| + | } |
| + | if ((magic == cpu_to_le32(UFS_MAGIC)) |
| + | || (magic == cpu_to_le32(UFS2_MAGIC)) |
| + | || (magic == cpu_to_le32(UFS_MAGIC_FEA)) |
| + | || (magic == cpu_to_le32(UFS_MAGIC_LFN)) |
| + | ) { |
| + | dbg("magic 0x%08x(le)", magic); |
| + | goto found; |
| + | } |
| + | } |
| + | return -1; |
| + | |
| + | found: |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "ufs"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,260 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count) |
| + | { |
| + | unsigned i, j; |
| + | uint16_t c; |
| + | |
| + | j = 0; |
| + | for (i = 0; i + 2 <= count; i += 2) { |
| + | if (endianess == LE) |
| + | c = (buf[i+1] << 8) | buf[i]; |
| + | else |
| + | c = (buf[i] << 8) | buf[i+1]; |
| + | if (c == 0) { |
| + | str[j] = '\0'; |
| + | break; |
| + | } else if (c < 0x80) { |
| + | if (j+1 >= len) |
| + | break; |
| + | str[j++] = (uint8_t) c; |
| + | } else if (c < 0x800) { |
| + | if (j+2 >= len) |
| + | break; |
| + | str[j++] = (uint8_t) (0xc0 | (c >> 6)); |
| + | str[j++] = (uint8_t) (0x80 | (c & 0x3f)); |
| + | } else { |
| + | if (j+3 >= len) |
| + | break; |
| + | str[j++] = (uint8_t) (0xe0 | (c >> 12)); |
| + | str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); |
| + | str[j++] = (uint8_t) (0x80 | (c & 0x3f)); |
| + | } |
| + | } |
| + | str[j] = '\0'; |
| + | } |
| + | |
| + | static const char *usage_to_string(enum volume_id_usage usage_id) |
| + | { |
| + | switch (usage_id) { |
| + | case VOLUME_ID_FILESYSTEM: |
| + | return "filesystem"; |
| + | case VOLUME_ID_PARTITIONTABLE: |
| + | return "partitiontable"; |
| + | case VOLUME_ID_OTHER: |
| + | return "other"; |
| + | case VOLUME_ID_RAID: |
| + | return "raid"; |
| + | case VOLUME_ID_DISKLABEL: |
| + | return "disklabel"; |
| + | case VOLUME_ID_CRYPTO: |
| + | return "crypto"; |
| + | case VOLUME_ID_UNPROBED: |
| + | return "unprobed"; |
| + | case VOLUME_ID_UNUSED: |
| + | return "unused"; |
| + | } |
| + | return NULL; |
| + | } |
| + | |
| + | void volume_id_set_usage_part(struct volume_id_partition *part, enum volume_id_usage usage_id) |
| + | { |
| + | part->usage_id = usage_id; |
| + | part->usage = usage_to_string(usage_id); |
| + | } |
| + | |
| + | void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id) |
| + | { |
| + | id->usage_id = usage_id; |
| + | id->usage = usage_to_string(usage_id); |
| + | } |
| + | |
| + | void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count) |
| + | { |
| + | memcpy(id->label_raw, buf, count); |
| + | id->label_raw_len = count; |
| + | } |
| + | |
| + | #ifdef NOT_NEEDED |
| + | static size_t strnlen(const char *s, size_t maxlen) |
| + | { |
| + | size_t i; |
| + | if (!maxlen) return 0; |
| + | if (!s) return 0; |
| + | for (i = 0; *s && i < maxlen; ++s) ++i; |
| + | return i; |
| + | } |
| + | #endif |
| + | |
| + | void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count) |
| + | { |
| + | unsigned i; |
| + | |
| + | memcpy(id->label, buf, count); |
| + | |
| + | /* remove trailing whitespace */ |
| + | i = strnlen(id->label, count); |
| + | while (i--) { |
| + | if (!isspace(id->label[i])) |
| + | break; |
| + | } |
| + | id->label[i+1] = '\0'; |
| + | } |
| + | |
| + | void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count) |
| + | { |
| + | volume_id_set_unicode16(id->label, sizeof(id->label), buf, endianess, count); |
| + | } |
| + | |
| + | void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format) |
| + | { |
| + | unsigned i; |
| + | unsigned count = 0; |
| + | |
| + | switch(format) { |
| + | case UUID_DOS: |
| + | count = 4; |
| + | break; |
| + | case UUID_NTFS: |
| + | case UUID_HFS: |
| + | count = 8; |
| + | break; |
| + | case UUID_DCE: |
| + | count = 16; |
| + | break; |
| + | case UUID_DCE_STRING: |
| + | count = 36; |
| + | break; |
| + | } |
| + | memcpy(id->uuid_raw, buf, count); |
| + | id->uuid_raw_len = count; |
| + | |
| + | /* if set, create string in the same format, the native platform uses */ |
| + | for (i = 0; i < count; i++) |
| + | if (buf[i] != 0) |
| + | goto set; |
| + | return; |
| + | |
| + | set: |
| + | switch(format) { |
| + | case UUID_DOS: |
| + | sprintf(id->uuid, "%02X%02X-%02X%02X", |
| + | buf[3], buf[2], buf[1], buf[0]); |
| + | break; |
| + | case UUID_NTFS: |
| + | sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X", |
| + | buf[7], buf[6], buf[5], buf[4], |
| + | buf[3], buf[2], buf[1], buf[0]); |
| + | break; |
| + | case UUID_HFS: |
| + | sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X", |
| + | buf[0], buf[1], buf[2], buf[3], |
| + | buf[4], buf[5], buf[6], buf[7]); |
| + | break; |
| + | case UUID_DCE: |
| + | sprintf(id->uuid, |
| + | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", |
| + | buf[0], buf[1], buf[2], buf[3], |
| + | buf[4], buf[5], |
| + | buf[6], buf[7], |
| + | buf[8], buf[9], |
| + | buf[10], buf[11], buf[12], buf[13], buf[14],buf[15]); |
| + | break; |
| + | case UUID_DCE_STRING: |
| + | memcpy(id->uuid, buf, count); |
| + | id->uuid[count] = '\0'; |
| + | break; |
| + | } |
| + | } |
| + | |
| + | void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len) |
| + | { |
| + | ssize_t buf_len; |
| + | |
| + | dbg("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len); |
| + | /* check if requested area fits in superblock buffer */ |
| + | if (off + len <= SB_BUFFER_SIZE) { |
| + | if (id->sbbuf == NULL) { |
| + | id->sbbuf = xmalloc(SB_BUFFER_SIZE); |
| + | } |
| + | |
| + | /* check if we need to read */ |
| + | if ((off + len) > id->sbbuf_len) { |
| + | dbg("read sbbuf len:0x%llx", (unsigned long long) (off + len)); |
| + | xlseek(id->fd, 0, SEEK_SET); |
| + | buf_len = full_read(id->fd, id->sbbuf, off + len); |
| + | if (buf_len < 0) { |
| + | dbg("read failed (%s)", strerror(errno)); |
| + | return NULL; |
| + | } |
| + | dbg("got 0x%zx (%zi) bytes", buf_len, buf_len); |
| + | id->sbbuf_len = buf_len; |
| + | if (buf_len < off + len) { |
| + | dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len); |
| + | return NULL; |
| + | } |
| + | } |
| + | |
| + | return &(id->sbbuf[off]); |
| + | } |
| + | |
| + | if (len > SEEK_BUFFER_SIZE) { |
| + | dbg("seek buffer too small %d", SEEK_BUFFER_SIZE); |
| + | return NULL; |
| + | } |
| + | |
| + | /* get seek buffer */ |
| + | if (id->seekbuf == NULL) { |
| + | id->seekbuf = xmalloc(SEEK_BUFFER_SIZE); |
| + | } |
| + | |
| + | /* check if we need to read */ |
| + | if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) { |
| + | dbg("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len); |
| + | xlseek(id->fd, off, SEEK_SET); |
| + | buf_len = full_read(id->fd, id->seekbuf, len); |
| + | if (buf_len < 0) { |
| + | dbg("read failed (%s)", strerror(errno)); |
| + | return NULL; |
| + | } |
| + | dbg("got 0x%zx (%zi) bytes", buf_len, buf_len); |
| + | id->seekbuf_off = off; |
| + | id->seekbuf_len = buf_len; |
| + | if (buf_len < len) { |
| + | dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len); |
| + | return NULL; |
| + | } |
| + | } |
| + | |
| + | return &(id->seekbuf[off - id->seekbuf_off]); |
| + | } |
| + | |
| + | void volume_id_free_buffer(struct volume_id *id) |
| + | { |
| + | free(id->sbbuf); |
| + | id->sbbuf = NULL; |
| + | id->sbbuf_len = 0; |
| + | free(id->seekbuf); |
| + | id->seekbuf = NULL; |
| + | id->seekbuf_len = 0; |
| + | } |
| @@ -0,0 +1,68 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct via_meta { |
| + | uint16_t signature; |
| + | uint8_t version_number; |
| + | struct via_array { |
| + | uint16_t disk_bits; |
| + | uint8_t disk_array_ex; |
| + | uint32_t capacity_low; |
| + | uint32_t capacity_high; |
| + | uint32_t serial_checksum; |
| + | } __attribute((packed)) array; |
| + | uint32_t serial_checksum[8]; |
| + | uint8_t checksum; |
| + | } __attribute__((packed)); |
| + | |
| + | #define VIA_SIGNATURE 0xAA55 |
| + | |
| + | int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | uint64_t meta_off; |
| + | struct via_meta *via; |
| + | |
| + | dbg("probing at offset 0x%llx, size 0x%llx", |
| + | (unsigned long long) off, (unsigned long long) size); |
| + | |
| + | if (size < 0x10000) |
| + | return -1; |
| + | |
| + | meta_off = ((size / 0x200)-1) * 0x200; |
| + | |
| + | via = volume_id_get_buffer(id, off + meta_off, 0x200); |
| + | if (via == NULL) |
| + | return -1; |
| + | |
| + | if (via->signature != cpu_to_le16(VIA_SIGNATURE)) |
| + | return -1; |
| + | |
| + | if (via->version_number > 1) |
| + | return -1; |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_RAID); |
| + | id->type_version[0] = '0' + via->version_number; |
| + | id->type_version[1] = '\0'; |
| + | id->type = "via_raid_member"; |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,214 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | typedef int (*raid_probe_fptr)(struct volume_id *id, uint64_t off, uint64_t size); |
| + | typedef int (*probe_fptr)(struct volume_id *id, uint64_t off); |
| + | |
| + | static const raid_probe_fptr raid1[] = { |
| + | #if ENABLE_FEATURE_VOLUMEID_LINUXRAID |
| + | volume_id_probe_linux_raid, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_ISWRAID |
| + | volume_id_probe_intel_software_raid, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_LSIRAID |
| + | volume_id_probe_lsi_mega_raid, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_VIARAID |
| + | volume_id_probe_via_raid, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_SILICONRAID |
| + | volume_id_probe_silicon_medley_raid, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_NVIDIARAID |
| + | volume_id_probe_nvidia_raid, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_PROMISERAID |
| + | volume_id_probe_promise_fasttrack_raid, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_HIGHPOINTRAID |
| + | volume_id_probe_highpoint_45x_raid, |
| + | #endif |
| + | }; |
| + | |
| + | static const probe_fptr raid2[] = { |
| + | #if ENABLE_FEATURE_VOLUMEID_LVM |
| + | volume_id_probe_lvm1, |
| + | volume_id_probe_lvm2, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_HIGHPOINTRAID |
| + | volume_id_probe_highpoint_37x_raid, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_LUKS |
| + | volume_id_probe_luks, |
| + | #endif |
| + | }; |
| + | |
| + | /* signature in the first block, only small buffer needed */ |
| + | static const probe_fptr fs1[] = { |
| + | #if ENABLE_FEATURE_VOLUMEID_FAT |
| + | volume_id_probe_vfat, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_MAC |
| + | volume_id_probe_mac_partition_map, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_XFS |
| + | volume_id_probe_xfs, |
| + | #endif |
| + | }; |
| + | |
| + | /* fill buffer with maximum */ |
| + | static const probe_fptr fs2[] = { |
| + | #if ENABLE_FEATURE_VOLUMEID_LINUXSWAP |
| + | volume_id_probe_linux_swap, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_EXT |
| + | volume_id_probe_ext, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_REISERFS |
| + | volume_id_probe_reiserfs, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_JFS |
| + | volume_id_probe_jfs, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_UDF |
| + | volume_id_probe_udf, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_ISO9660 |
| + | volume_id_probe_iso9660, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_HFS |
| + | volume_id_probe_hfs_hfsplus, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_UFS |
| + | volume_id_probe_ufs, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_NTFS |
| + | volume_id_probe_ntfs, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_CRAMFS |
| + | volume_id_probe_cramfs, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_ROMFS |
| + | volume_id_probe_romfs, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_HPFS |
| + | volume_id_probe_hpfs, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_SYSV |
| + | volume_id_probe_sysv, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_MINIX |
| + | volume_id_probe_minix, |
| + | #endif |
| + | #if ENABLE_FEATURE_VOLUMEID_OCFS2 |
| + | volume_id_probe_ocfs2, |
| + | #endif |
| + | }; |
| + | |
| + | int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size) |
| + | { |
| + | int i; |
| + | |
| + | if (id == NULL) |
| + | return -EINVAL; |
| + | |
| + | /* probe for raid first, cause fs probes may be successful on raid members */ |
| + | if (size) { |
| + | for (i = 0; i < ARRAY_SIZE(raid1); i++) |
| + | if (raid1[i](id, off, size) == 0) |
| + | goto ret; |
| + | } |
| + | |
| + | for (i = 0; i < ARRAY_SIZE(raid2); i++) |
| + | if (raid2[i](id, off) == 0) |
| + | goto ret; |
| + | |
| + | /* signature in the first block, only small buffer needed */ |
| + | for (i = 0; i < ARRAY_SIZE(fs1); i++) |
| + | if (fs1[i](id, off) == 0) |
| + | goto ret; |
| + | |
| + | /* fill buffer with maximum */ |
| + | volume_id_get_buffer(id, 0, SB_BUFFER_SIZE); |
| + | |
| + | for (i = 0; i < ARRAY_SIZE(fs2); i++) |
| + | if (fs2[i](id, off) == 0) |
| + | goto ret; |
| + | return -1; |
| + | |
| + | ret: |
| + | /* If the filestystem in recognized, we free the allocated buffers, |
| + | otherwise they will stay in place for the possible next probe call */ |
| + | volume_id_free_buffer(id); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | /* open volume by device node */ |
| + | struct volume_id *volume_id_open_node(const char *path) |
| + | { |
| + | struct volume_id *id; |
| + | int fd; |
| + | |
| + | fd = xopen(path, O_RDONLY); |
| + | id = xzalloc(sizeof(struct volume_id)); |
| + | id->fd = fd; |
| + | ///* close fd on device close */ |
| + | //id->fd_close = 1; |
| + | |
| + | return id; |
| + | } |
| + | |
| + | #ifdef UNUSED |
| + | /* open volume by major/minor */ |
| + | struct volume_id *volume_id_open_dev_t(dev_t devt) |
| + | { |
| + | struct volume_id *id; |
| + | char *tmp_node[VOLUME_ID_PATH_MAX]; |
| + | |
| + | tmp_node = xasprintf("/dev/.volume_id-%u-%u-%u", |
| + | (unsigned)getpid(), (unsigned)major(devt), (unsigned)minor(devt)); |
| + | |
| + | /* create temporary node to open block device */ |
| + | unlink(tmp_node); |
| + | if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0) |
| + | bb_perror_msg_and_die("cannot mknod(%s)", tmp_node); |
| + | |
| + | id = volume_id_open_node(tmp_node); |
| + | unlink(tmp_node); |
| + | free(tmp_node); |
| + | return id; |
| + | } |
| + | #endif |
| + | |
| + | void free_volume_id(struct volume_id *id) |
| + | { |
| + | if (id == NULL) |
| + | return; |
| + | |
| + | //if (id->fd_close != 0) - always true |
| + | close(id->fd); |
| + | volume_id_free_buffer(id); |
| + | free(id->partitions); |
| + | free(id); |
| + | } |
| @@ -0,0 +1,220 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2005 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "libbb.h" |
| + | #include "volume_id.h" |
| + | |
| + | |
| + | #define dbg(...) ((void)0) |
| + | |
| + | |
| + | /* volume_id.h */ |
| + | |
| + | #define VOLUME_ID_VERSION 48 |
| + | |
| + | #define VOLUME_ID_LABEL_SIZE 64 |
| + | #define VOLUME_ID_UUID_SIZE 36 |
| + | #define VOLUME_ID_FORMAT_SIZE 32 |
| + | #define VOLUME_ID_PARTITIONS_MAX 256 |
| + | |
| + | enum volume_id_usage { |
| + | VOLUME_ID_UNUSED, |
| + | VOLUME_ID_UNPROBED, |
| + | VOLUME_ID_OTHER, |
| + | VOLUME_ID_FILESYSTEM, |
| + | VOLUME_ID_PARTITIONTABLE, |
| + | VOLUME_ID_RAID, |
| + | VOLUME_ID_DISKLABEL, |
| + | VOLUME_ID_CRYPTO, |
| + | }; |
| + | |
| + | struct volume_id_partition { |
| + | enum volume_id_usage usage_id; |
| + | const char *usage; |
| + | const char *type; |
| + | uint64_t off; |
| + | uint64_t len; |
| + | uint8_t partition_type_raw; |
| + | }; |
| + | |
| + | struct volume_id { |
| + | uint8_t label_raw[VOLUME_ID_LABEL_SIZE]; |
| + | size_t label_raw_len; |
| + | char label[VOLUME_ID_LABEL_SIZE+1]; |
| + | uint8_t uuid_raw[VOLUME_ID_UUID_SIZE]; |
| + | size_t uuid_raw_len; |
| + | char uuid[VOLUME_ID_UUID_SIZE+1]; |
| + | enum volume_id_usage usage_id; |
| + | const char *usage; |
| + | const char *type; |
| + | char type_version[VOLUME_ID_FORMAT_SIZE]; |
| + | |
| + | struct volume_id_partition *partitions; |
| + | size_t partition_count; |
| + | |
| + | int fd; |
| + | uint8_t *sbbuf; |
| + | uint8_t *seekbuf; |
| + | size_t sbbuf_len; |
| + | uint64_t seekbuf_off; |
| + | size_t seekbuf_len; |
| + | // int fd_close:1; |
| + | }; |
| + | |
| + | struct volume_id *volume_id_open_node(const char *path); |
| + | int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size); |
| + | void free_volume_id(struct volume_id *id); |
| + | |
| + | /* util.h */ |
| + | |
| + | /* size of superblock buffer, reiserfs block is at 64k */ |
| + | #define SB_BUFFER_SIZE 0x11000 |
| + | /* size of seek buffer, FAT cluster is 32k max */ |
| + | #define SEEK_BUFFER_SIZE 0x10000 |
| + | |
| + | #define bswap16(x) (uint16_t) ( \ |
| + | (((uint16_t)(x) & 0x00ffu) << 8) | \ |
| + | (((uint16_t)(x) & 0xff00u) >> 8)) |
| + | |
| + | #define bswap32(x) (uint32_t) ( \ |
| + | (((uint32_t)(x) & 0xff000000u) >> 24) | \ |
| + | (((uint32_t)(x) & 0x00ff0000u) >> 8) | \ |
| + | (((uint32_t)(x) & 0x0000ff00u) << 8) | \ |
| + | (((uint32_t)(x) & 0x000000ffu) << 24)) |
| + | |
| + | #define bswap64(x) (uint64_t) ( \ |
| + | (((uint64_t)(x) & 0xff00000000000000ull) >> 56) | \ |
| + | (((uint64_t)(x) & 0x00ff000000000000ull) >> 40) | \ |
| + | (((uint64_t)(x) & 0x0000ff0000000000ull) >> 24) | \ |
| + | (((uint64_t)(x) & 0x000000ff00000000ull) >> 8) | \ |
| + | (((uint64_t)(x) & 0x00000000ff000000ull) << 8) | \ |
| + | (((uint64_t)(x) & 0x0000000000ff0000ull) << 24) | \ |
| + | (((uint64_t)(x) & 0x000000000000ff00ull) << 40) | \ |
| + | (((uint64_t)(x) & 0x00000000000000ffull) << 56)) |
| + | |
| + | #if BB_LITTLE_ENDIAN |
| + | #define le16_to_cpu(x) (x) |
| + | #define le32_to_cpu(x) (x) |
| + | #define le64_to_cpu(x) (x) |
| + | #define be16_to_cpu(x) bswap16(x) |
| + | #define be32_to_cpu(x) bswap32(x) |
| + | #define cpu_to_le16(x) (x) |
| + | #define cpu_to_le32(x) (x) |
| + | #define cpu_to_be32(x) bswap32(x) |
| + | #else |
| + | #define le16_to_cpu(x) bswap16(x) |
| + | #define le32_to_cpu(x) bswap32(x) |
| + | #define le64_to_cpu(x) bswap64(x) |
| + | #define be16_to_cpu(x) (x) |
| + | #define be32_to_cpu(x) (x) |
| + | #define cpu_to_le16(x) bswap16(x) |
| + | #define cpu_to_le32(x) bswap32(x) |
| + | #define cpu_to_be32(x) (x) |
| + | #endif |
| + | |
| + | enum uuid_format { |
| + | UUID_DCE_STRING, |
| + | UUID_DCE, |
| + | UUID_DOS, |
| + | UUID_NTFS, |
| + | UUID_HFS, |
| + | }; |
| + | |
| + | enum endian { |
| + | LE = 0, |
| + | BE = 1 |
| + | }; |
| + | |
| + | void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count); |
| + | void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id); |
| + | void volume_id_set_usage_part(struct volume_id_partition *part, enum volume_id_usage usage_id); |
| + | void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count); |
| + | void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count); |
| + | void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count); |
| + | void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format); |
| + | void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len); |
| + | void volume_id_free_buffer(struct volume_id *id); |
| + | |
| + | |
| + | /* Probe routines */ |
| + | |
| + | /* RAID */ |
| + | |
| + | int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off); |
| + | int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size); |
| + | |
| + | int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size); |
| + | |
| + | int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size); |
| + | |
| + | int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size); |
| + | |
| + | int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size); |
| + | |
| + | int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size); |
| + | |
| + | int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size); |
| + | |
| + | int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size); |
| + | |
| + | int volume_id_probe_lvm1(struct volume_id *id, uint64_t off); |
| + | int volume_id_probe_lvm2(struct volume_id *id, uint64_t off); |
| + | |
| + | /* FS */ |
| + | |
| + | int volume_id_probe_cramfs(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_ext(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_vfat(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_hpfs(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_iso9660(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_jfs(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_luks(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_mac_partition_map(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_minix(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_ntfs(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_romfs(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_sysv(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_udf(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_ufs(struct volume_id *id, uint64_t off); |
| + | |
| + | int volume_id_probe_xfs(struct volume_id *id, uint64_t off); |
| @@ -0,0 +1,59 @@ | |
| + | /* |
| + | * volume_id - reads filesystem label and uuid |
| + | * |
| + | * Copyright (C) 2004 Kay Sievers <[email protected]> |
| + | * |
| + | * This library is free software; you can redistribute it and/or |
| + | * modify it under the terms of the GNU Lesser General Public |
| + | * License as published by the Free Software Foundation; either |
| + | * version 2.1 of the License, or (at your option) any later version. |
| + | * |
| + | * This library is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | * Lesser General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU Lesser General Public |
| + | * License along with this library; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | */ |
| + | |
| + | #include "volume_id_internal.h" |
| + | |
| + | struct xfs_super_block { |
| + | uint8_t magic[4]; |
| + | uint32_t blocksize; |
| + | uint64_t dblocks; |
| + | uint64_t rblocks; |
| + | uint32_t dummy1[2]; |
| + | uint8_t uuid[16]; |
| + | uint32_t dummy2[15]; |
| + | uint8_t fname[12]; |
| + | uint32_t dummy3[2]; |
| + | uint64_t icount; |
| + | uint64_t ifree; |
| + | uint64_t fdblocks; |
| + | } __attribute__((__packed__)); |
| + | |
| + | int volume_id_probe_xfs(struct volume_id *id, uint64_t off) |
| + | { |
| + | struct xfs_super_block *xs; |
| + | |
| + | dbg("probing at offset 0x%llx", (unsigned long long) off); |
| + | |
| + | xs = volume_id_get_buffer(id, off, 0x200); |
| + | if (xs == NULL) |
| + | return -1; |
| + | |
| + | if (memcmp(xs->magic, "XFSB", 4) != 0) |
| + | return -1; |
| + | |
| + | volume_id_set_label_raw(id, xs->fname, 12); |
| + | volume_id_set_label_string(id, xs->fname, 12); |
| + | volume_id_set_uuid(id, xs->uuid, UUID_DCE); |
| + | |
| + | volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
| + | id->type = "xfs"; |
| + | |
| + | return 0; |
| + | } |