diff options
Diffstat (limited to '')
-rw-r--r-- | libblkid/src/superblocks/gfs.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/libblkid/src/superblocks/gfs.c b/libblkid/src/superblocks/gfs.c new file mode 100644 index 0000000..37a74b1 --- /dev/null +++ b/libblkid/src/superblocks/gfs.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +/* Common gfs/gfs2 constants: */ +#define GFS_LOCKNAME_LEN 64 + +/* gfs1 constants: */ +#define GFS_FORMAT_FS 1309 +#define GFS_FORMAT_MULTI 1401 + +struct gfs2_meta_header { + uint32_t mh_magic; + uint32_t mh_type; + uint64_t __pad0; /* Was generation number in gfs1 */ + uint32_t mh_format; + uint32_t __pad1; /* Was incarnation number in gfs1 */ +}; + +struct gfs2_inum { + uint64_t no_formal_ino; + uint64_t no_addr; +}; + +struct gfs2_sb { + struct gfs2_meta_header sb_header; + + uint32_t sb_fs_format; + uint32_t sb_multihost_format; + uint32_t __pad0; /* Was superblock flags in gfs1 */ + + uint32_t sb_bsize; + uint32_t sb_bsize_shift; + uint32_t __pad1; /* Was journal segment size in gfs1 */ + + struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ + struct gfs2_inum sb_root_dir; + + char sb_lockproto[GFS_LOCKNAME_LEN]; + char sb_locktable[GFS_LOCKNAME_LEN]; + + struct gfs2_inum __pad3; /* Was quota inode in gfs1 */ + struct gfs2_inum __pad4; /* Was license inode in gfs1 */ + uint8_t sb_uuid[16]; /* The UUID maybe 0 for backwards compat */ +} __attribute__((packed)); + + + +static int probe_gfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct gfs2_sb *sbd; + + sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); + if (!sbd) + return errno ? -errno : 1; + + if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS && + be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI) + { + if (*sbd->sb_locktable) + blkid_probe_set_label(pr, + (unsigned char *) sbd->sb_locktable, + sizeof(sbd->sb_locktable)); + + blkid_probe_set_uuid(pr, sbd->sb_uuid); + return 0; + } + + return 1; +} + +static inline int gfs2_format_is_valid(uint32_t format) +{ + return (format >= 1800 && format < 1900); +} +static inline int gfs2_multiformat_is_valid(uint32_t multi) +{ + return (multi >= 1900 && multi < 2000); +} + +static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct gfs2_sb *sbd; + + sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); + if (!sbd) + return errno ? -errno : 1; + + if (gfs2_format_is_valid(be32_to_cpu(sbd->sb_fs_format)) && + gfs2_multiformat_is_valid(be32_to_cpu(sbd->sb_multihost_format))) + { + if (*sbd->sb_locktable) + blkid_probe_set_label(pr, + (unsigned char *) sbd->sb_locktable, + sizeof(sbd->sb_locktable)); + blkid_probe_set_uuid(pr, sbd->sb_uuid); + blkid_probe_set_version(pr, "1"); + blkid_probe_set_block_size(pr, be32_to_cpu(sbd->sb_bsize)); + return 0; + } + return 1; +} + +const struct blkid_idinfo gfs_idinfo = +{ + .name = "gfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_gfs, + .minsz = 32 * 1024 * 1024, /* minimal size of GFS journal */ + .magics = + { + { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 }, + { NULL } + } +}; + +const struct blkid_idinfo gfs2_idinfo = +{ + .name = "gfs2", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_gfs2, + .minsz = 32 * 1024 * 1024, /* minimal size of GFS journal */ + .magics = + { + { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 }, + { NULL } + } +}; + |