* %End-Header%
*/
+#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
{
const unsigned char *end = label + len - 1;
- while ((*end == ' ' || *end == 0) && end >= label)
+ while (end >= label && (*end == ' ' || *end == 0))
--end;
- if (end >= label) {
- label = label;
+ if (end >= label)
return end - label + 1;
- }
return 0;
}
if (blkid_llseek(fd, offset, 0) < 0 ||
read(fd, buf, 4096) != 4096)
return -BLKID_ERR_IO;
-
/* Check for magic number */
if (memcmp("\251+N\374", buf, 4) && memcmp("\374N+\251", buf, 4))
return -BLKID_ERR_PARAM;
blkid_le32(es->s_feature_incompat),
blkid_le32(es->s_feature_ro_compat)));
- if (strlen(es->s_volume_name))
+ if (es->s_volume_name[0])
label = es->s_volume_name;
blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name));
#ifdef __linux__
struct utsname uts;
FILE *f;
- char buf[1024], *cp, *t;
- int i;
+ char buf[1024], *cp;
+ int namesz;
if (uname(&uts))
return (0);
f = fopen(buf, "r");
if (!f)
return (0);
+
+ namesz = strlen(fs_name);
+
while (!feof(f)) {
if (!fgets(buf, sizeof(buf), f))
break;
cp++;
else
cp = buf;
- i = strlen(cp);
- if (i > 3) {
- t = cp + i - 3;
- if (!strcmp(t, ".ko"))
- *t = 0;
- }
- if (!strcmp(cp, fs_name)) {
+ if (!strncmp(cp, fs_name, namesz) &&
+ (!strcmp(cp + namesz, ".ko") ||
+ !strcmp(cp + namesz, ".ko.gz"))) {
fclose(f);
return (1);
}
return (0);
}
+static int linux_version_code(void)
+{
+#ifdef __linux__
+ struct utsname ut;
+ static int version_code = -1;
+ int major, minor, rev;
+ char *endptr;
+ const char *cp;
+
+ if (version_code > 0)
+ return version_code;
+
+ if (uname(&ut))
+ return 0;
+ cp = ut.release;
+
+ major = strtol(cp, &endptr, 10);
+ if (cp == endptr || *endptr != '.')
+ return 0;
+ cp = endptr + 1;
+ minor = strtol(cp, &endptr, 10);
+ if (cp == endptr || *endptr != '.')
+ return 0;
+ cp = endptr + 1;
+ rev = strtol(cp, &endptr, 10);
+ if (cp == endptr)
+ return 0;
+ version_code = (((major * 256) + minor) * 256) + rev;
+ return version_code;
+#else
+ return 0;
+#endif
+}
+
+#define EXT4_SUPPORTS_EXT2 (2 * 65536 + 6*256 + 29)
+
+static int system_supports_ext2(void)
+{
+ static time_t last_check = 0;
+ static int ret = -1;
+ time_t now = time(0);
+
+ if (ret != -1 || (now - last_check) < 5)
+ return ret;
+ last_check = now;
+ ret = (fs_proc_check("ext2") || check_for_modules("ext2"));
+ return ret;
+}
+
static int system_supports_ext4(void)
{
static time_t last_check = 0;
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
return -BLKID_ERR_PARAM;
+ /*
+ * If the filesystem does not have a journal and ext2 and ext4
+ * is not present, then force this to be detected as an
+ * ext4dev filesystem.
+ */
+ if (!(blkid_le32(es->s_feature_compat) &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+ !system_supports_ext2() && !system_supports_ext4() &&
+ system_supports_ext4dev() &&
+ linux_version_code() >= EXT4_SUPPORTS_EXT2)
+ goto force_ext4dev;
+
/*
* If the filesystem is marked as OK for use by in-development
* filesystem code, but ext4dev is not supported, and ext4 is,
} else
return -BLKID_ERR_PARAM;
+force_ext4dev:
get_ext2_info(probe->dev, id, buf);
return 0;
}
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
return -BLKID_ERR_PARAM;
+ /*
+ * If the filesystem does not have a journal and ext2 is not
+ * present, then force this to be detected as an ext2
+ * filesystem.
+ */
+ if (!(blkid_le32(es->s_feature_compat) &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+ !system_supports_ext2() && system_supports_ext4() &&
+ linux_version_code() >= EXT4_SUPPORTS_EXT2)
+ goto force_ext4;
+
/* Ext4 has at least one feature which ext3 doesn't understand */
if (!(blkid_le32(es->s_feature_ro_compat) &
EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
return -BLKID_ERR_PARAM;
+force_ext4:
/*
* If the filesystem is a OK for use by in-development
* filesystem code, and ext4dev is supported or ext4 is not
EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
return -BLKID_ERR_PARAM;
+ /*
+ * If ext2 is not present, but ext4 or ext4dev are, then
+ * disclaim we are ext2
+ */
+ if (!system_supports_ext2() &&
+ (system_supports_ext4() || system_supports_ext4dev()) &&
+ linux_version_code() >= EXT4_SUPPORTS_EXT2)
+ return -BLKID_ERR_PARAM;
+
get_ext2_info(probe->dev, id, buf);
return 0;
}
int count;
next_sect_off = (next - 2) * vs->vs_cluster_size;
- next_off = (start_data_sect + next_sect_off) *
+ next_off = (__u64) (start_data_sect + next_sect_off) *
sector_size;
dir = (struct vfat_dir_entry *)
break;
/* get FAT entry */
- fat_entry_off = (reserved * sector_size) +
+ fat_entry_off =
+ ((unsigned int) reserved *
+ (unsigned int) sector_size) +
(next * sizeof(__u32));
buf = get_buffer(probe, fat_entry_off, buf_size);
if (buf == NULL)
js = (struct jfs_super_block *)buf;
- if (blkid_le32(js->js_bsize) != (1 << blkid_le16(js->js_l2bsize)))
+ if (blkid_le32(js->js_bsize) != (1U << blkid_le16(js->js_l2bsize)))
return 1;
- if (blkid_le32(js->js_pbsize) != (1 << blkid_le16(js->js_l2pbsize)))
+ if (blkid_le32(js->js_pbsize) != (1U << blkid_le16(js->js_l2pbsize)))
return 1;
if ((blkid_le16(js->js_l2bsize) - blkid_le16(js->js_l2pbsize)) !=
return 0;
}
-static int probe_zfs(struct blkid_probe *probe, struct blkid_magic *id,
- unsigned char *buf)
+static int probe_zfs(struct blkid_probe *probe __BLKID_ATTR((unused)),
+ struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf __BLKID_ATTR((unused)))
{
#if 0
char *vdev_label;
struct blkid_magic *id __BLKID_ATTR((unused)),
unsigned char *buf)
{
- char uuid[40];
+ char uuid[41];
/* 168 is the offset to the 40 character uuid:
* http://luks.endorphin.org/LUKS-on-disk-format.pdf */
strncpy(uuid, (char *) buf+168, 40);
- blkid_set_tag(probe->dev, "UUID", uuid, sizeof(uuid));
+ uuid[40] = 0;
+ blkid_set_tag(probe->dev, "UUID", uuid, 40);
return 0;
}
(block sizes larger than 2K will be null padded) */
for (bs = 1; bs < 16; bs++) {
isosb = (struct iso_volume_descriptor *)
- get_buffer(probe, bs*2048+32768, sizeof(isosb));
+ get_buffer(probe, (blkid_loff_t) bs*2048+32768,
+ sizeof(*isosb));
if (!isosb)
return 1;
if (isosb->vd_id[0])
if (j > 1) {
isosb = (struct iso_volume_descriptor *)
get_buffer(probe, j*bs*2048+32768,
- sizeof(isosb));
+ sizeof(*isosb));
if (!isosb)
return 1;
}
str[j] = '\0';
}
+static void unicode_16le_to_utf8(unsigned char *str, int out_len,
+ const unsigned char *buf, int in_len)
+{
+ int i, j;
+ unsigned int c;
+
+ for (i = j = 0; i + 2 <= in_len; i += 2) {
+ c = (buf[i+1] << 8) | buf[i];
+ if (c == 0) {
+ str[j] = '\0';
+ break;
+ } else if (c < 0x80) {
+ if (j+1 >= out_len)
+ break;
+ str[j++] = (unsigned char) c;
+ } else if (c < 0x800) {
+ if (j+2 >= out_len)
+ break;
+ str[j++] = (unsigned char) (0xc0 | (c >> 6));
+ str[j++] = (unsigned char) (0x80 | (c & 0x3f));
+ } else {
+ if (j+3 >= out_len)
+ break;
+ str[j++] = (unsigned char) (0xe0 | (c >> 12));
+ str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f));
+ str[j++] = (unsigned char) (0x80 | (c & 0x3f));
+ }
+ }
+ str[j] = '\0';
+}
+
static int probe_hfs(struct blkid_probe *probe __BLKID_ATTR((unused)),
struct blkid_magic *id __BLKID_ATTR((unused)),
unsigned char *buf)
{
- struct hfs_mdb *hfs = (struct hfs_mdb *) buf;
+ struct hfs_mdb *hfs = (struct hfs_mdb *)buf;
+ unsigned long long *uuid_ptr;
char uuid_str[17];
__u64 uuid;
(memcmp(hfs->embed_sig, "HX", 2) == 0))
return 1; /* Not hfs, but an embedded HFS+ */
- uuid = blkid_le64(*((unsigned long long *) hfs->finder_info.id));
+ uuid_ptr = (unsigned long long *)hfs->finder_info.id;
+ uuid = blkid_le64(*uuid_ptr);
if (uuid) {
sprintf(uuid_str, "%016llX", uuid);
blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
}
- blkid_set_tag(probe->dev, "LABEL", hfs->label, hfs->label_len);
+ blkid_set_tag(probe->dev, "LABEL", (char *)hfs->label, hfs->label_len);
return 0;
}
+#define HFSPLUS_SECTOR_SIZE 512
+
static int probe_hfsplus(struct blkid_probe *probe,
struct blkid_magic *id,
unsigned char *buf)
unsigned int leaf_node_size;
unsigned int leaf_block;
unsigned int label_len;
- int ext;
+ unsigned long long *uuid_ptr;
__u64 leaf_off, uuid;
char uuid_str[17], label[512];
+ int ext;
/* Check for a HFS+ volume embedded in a HFS volume */
if (memcmp(sbd->signature, "BD", 2) == 0) {
off = (alloc_first_block * 512) +
(embed_first_block * alloc_block_size);
buf = get_buffer(probe, off + (id->bim_kboff * 1024),
- sizeof(sbd));
+ sizeof(*sbd));
if (!buf)
return 1;
(memcmp(hfsplus->signature, "HX", 2) != 0))
return 1;
- uuid = blkid_le64(*((unsigned long long *) hfsplus->finder_info.id));
+ uuid_ptr = (unsigned long long *)hfsplus->finder_info.id;
+ uuid = blkid_le64(*uuid_ptr);
if (uuid) {
sprintf(uuid_str, "%016llX", uuid);
blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
}
blocksize = blkid_be32(hfsplus->blocksize);
+ if (blocksize < HFSPLUS_SECTOR_SIZE)
+ return 1;
+
memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
cat_block = blkid_be32(extents[0].start_block);
- buf = get_buffer(probe, off + (cat_block * blocksize), 0x2000);
+ buf = get_buffer(probe, off + ((__u64) cat_block * blocksize), 0x2000);
if (!buf)
return 0;
if (ext == HFSPLUS_EXTENT_COUNT)
return 0;
- leaf_off = (ext_block_start + leaf_block) * blocksize;
+ leaf_off = (__u64) (ext_block_start + leaf_block) * blocksize;
buf = get_buffer(probe, off + leaf_off, leaf_node_size);
if (!buf)
return 0;
label_len = blkid_be16(key->unicode_len) * 2;
- unicode_16be_to_utf8(label, sizeof(label), key->unicode, label_len);
+ unicode_16be_to_utf8((unsigned char *)label, sizeof(label),
+ key->unicode, label_len);
blkid_set_tag(probe->dev, "LABEL", label, 0);
return 0;
}
return 1;
}
- for (i=0, b=1, p=uuid, q= (char *) label->pv_uuid; i <= 32;
+ for (i=0, b=1, p=uuid, q= (char *) label->pv_uuid; i < LVM2_ID_LEN;
i++, b <<= 1) {
if (b & 0x4444440)
*p++ = '-';
}
static int probe_btrfs(struct blkid_probe *probe,
- struct blkid_magic *id,
+ struct blkid_magic *id __BLKID_ATTR((unused)),
unsigned char *buf)
{
struct btrfs_super_block *bs;
set_uuid(probe->dev, bs->fsid, 0);
return 0;
}
+
+static int probe_f2fs(struct blkid_probe *probe,
+ struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct f2fs_super_block *bs;
+
+ bs = (struct f2fs_super_block *)buf;
+ set_uuid(probe->dev, bs->uuid, 0);
+ return 0;
+}
+
+static uint64_t exfat_block_to_offset(const struct exfat_super_block *sb,
+ uint64_t block)
+{
+ return block << sb->block_bits;
+}
+
+static uint64_t exfat_cluster_to_block(const struct exfat_super_block *sb,
+ uint32_t cluster)
+{
+ return sb->cluster_block_start +
+ ((uint64_t)(cluster - EXFAT_FIRST_DATA_CLUSTER) << sb->bpc_bits);
+}
+
+static uint64_t exfat_cluster_to_offset(const struct exfat_super_block *sb,
+ uint32_t cluster)
+{
+ return exfat_block_to_offset(sb, exfat_cluster_to_block(sb, cluster));
+}
+
+static uint32_t exfat_next_cluster(struct blkid_probe *probe,
+ const struct exfat_super_block *sb,
+ uint32_t cluster)
+{
+ uint32_t *next;
+ uint64_t offset;
+
+ offset = exfat_block_to_offset(sb, sb->fat_block_start)
+ + (uint64_t) cluster * sizeof (cluster);
+ next = (uint32_t *)get_buffer(probe, offset, sizeof (uint32_t));
+
+ return next ? *next : 0;
+}
+
+static struct exfat_entry_label *find_exfat_entry_label(
+ struct blkid_probe *probe, const struct exfat_super_block *sb)
+{
+ uint32_t cluster = sb->rootdir_cluster;
+ uint64_t offset = exfat_cluster_to_offset(sb, cluster);
+ uint8_t *entry;
+ const size_t max_iter = 10000;
+ size_t i = 0;
+
+ for (; i < max_iter; ++i) {
+ entry = (uint8_t *)get_buffer(probe, offset, EXFAT_ENTRY_SIZE);
+ if (!entry)
+ return NULL;
+ if (entry[0] == EXFAT_ENTRY_EOD)
+ return NULL;
+ if (entry[0] == EXFAT_ENTRY_LABEL)
+ return (struct exfat_entry_label*) entry;
+
+ offset += EXFAT_ENTRY_SIZE;
+ if (offset % CLUSTER_SIZE(sb) == 0) {
+ cluster = exfat_next_cluster(probe, sb, cluster);
+ if (cluster < EXFAT_FIRST_DATA_CLUSTER)
+ return NULL;
+ if (cluster > EXFAT_LAST_DATA_CLUSTER)
+ return NULL;
+ offset = exfat_cluster_to_offset(sb, cluster);
+ }
+ }
+
+ return NULL;
+}
+
+static int probe_exfat(struct blkid_probe *probe,
+ struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct exfat_super_block *sb;
+ struct exfat_entry_label *label;
+ char uuid[40];
+
+ sb = (struct exfat_super_block *)buf;
+ if (!sb || CLUSTER_SIZE(sb) == 0) {
+ DBG(DEBUG_PROBE, printf("bad exfat superblock.\n"));
+ return errno ? - errno : 1;
+ }
+
+ label = find_exfat_entry_label(probe, sb);
+ if (label) {
+ unsigned char utf8_label[128];
+ unicode_16le_to_utf8(utf8_label, sizeof(utf8_label), label->name, label->length * 2);
+ blkid_set_tag(probe->dev, "LABEL", (char *) utf8_label, 0);
+ } else {
+ blkid_set_tag(probe->dev, "LABEL", "disk", 4);
+ }
+
+ memset(uuid, 0, sizeof (uuid));
+ snprintf(uuid, sizeof (uuid), "%02hhX%02hhX-%02hhX%02hhX",
+ sb->volume_serial[3], sb->volume_serial[2],
+ sb->volume_serial[1], sb->volume_serial[0]);
+ blkid_set_tag(probe->dev, "UUID", uuid, strlen(uuid));
+
+ return 0;
+}
+
/*
* Various filesystem magics that we can check for. Note that kboff and
* sboff are in kilobytes and bytes respectively. All magics are in
{ "iso9660", 32, 1, 5, "CD001", probe_iso9660 },
{ "iso9660", 32, 9, 5, "CDROM", probe_iso9660 },
{ "jfs", 32, 0, 4, "JFS1", probe_jfs },
- { "zfs", 8, 0, 8, "\0\0\x02\xf5\xb0\x07\xb1\x0c", probe_zfs },
- { "zfs", 8, 0, 8, "\x0c\xb1\x07\xb0\xf5\x02\0\0", probe_zfs },
- { "zfs", 264, 0, 8, "\0\0\x02\xf5\xb0\x07\xb1\x0c", probe_zfs },
- { "zfs", 264, 0, 8, "\x0c\xb1\x07\xb0\xf5\x02\0\0", probe_zfs },
+ /* ZFS has 128 root blocks (#4 is the first used), check only 6 of them */
+ { "zfs", 128, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs },
+ { "zfs", 128, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs },
+ { "zfs", 132, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs },
+ { "zfs", 132, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs },
+ { "zfs", 136, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs },
+ { "zfs", 136, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs },
+ { "zfs", 384, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs },
+ { "zfs", 384, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs },
+ { "zfs", 388, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs },
+ { "zfs", 388, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs },
+ { "zfs", 392, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs },
+ { "zfs", 392, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs },
{ "hfsplus", 1, 0, 2, "BD", probe_hfsplus },
{ "hfsplus", 1, 0, 2, "H+", probe_hfsplus },
{ "hfsplus", 1, 0, 2, "HX", probe_hfsplus },
{ "lvm2pv", 1, 0x018, 8, "LVM2 001", probe_lvm2 },
{ "lvm2pv", 1, 0x218, 8, "LVM2 001", probe_lvm2 },
{ "btrfs", 64, 0x40, 8, "_BHRfS_M", probe_btrfs },
+ { "f2fs", 1, 0, 4, "\x10\x20\xf5\xf2", probe_f2fs },
+ { "exfat", 0, 3, 8, "EXFAT ", probe_exfat },
{ NULL, 0, 0, 0, NULL, NULL }
};
unsigned char *buf;
const char *type, *value;
struct stat st;
- time_t diff, now;
+ time_t now;
+ double diff;
int idx;
if (!dev)
return NULL;
now = time(0);
- diff = now - dev->bid_time;
+ diff = difftime(now, dev->bid_time);
if (stat(dev->bid_name, &st) < 0) {
DBG(DEBUG_PROBE,
continue;
idx = id->bim_kboff + (id->bim_sboff >> 10);
- buf = get_buffer(&probe, idx << 10, 1024);
+ buf = get_buffer(&probe, (__u64) idx << 10, 1024);
if (!buf)
continue;
dev->bid_name, (long long)st.st_rdev, type));
}
- if (probe.sbbuf)
- free(probe.sbbuf);
- if (probe.buf)
- free(probe.buf);
+ free(probe.sbbuf);
+ free(probe.buf);
if (probe.fd >= 0)
close(probe.fd);