From 599b626127f420236b8757a1e9bccc8b07081a01 Mon Sep 17 00:00:00 2001 From: "kay.sievers@vrfy.org" Date: Wed, 5 May 2004 22:21:48 -0700 Subject: [PATCH] [PATCH] udev callout for reading filesystem labels On Fri, Apr 30, 2004 at 03:29:54PM -0700, Greg KH wrote: > On Thu, Apr 29, 2004 at 11:04:46PM +0200, Kay Sievers wrote: > > Hi, > > here is a small udev toy, which enables udev to name partitions by > > its filesystem label or uuid's. > > > > The following udev rule: > > > > KERNEL="sd*", PROGRAM="/sbin/udev_volume_id -M%M -m%m -u", SYMLINK="%c" > > > > creates a symlink with the uuid read from the filesystem. If no label or > > uuid is found the program exits with nonzero and the rule will fail. > > > > ext2, ext3, reiserfs, xfs, jfs, vfat, msdos volume labels are supported, > > ntfs and swap partitions can be recognized. > > > > It's possible to compile with klibc and the static binary takes 13kb. > > Very nice, I was wondering who was going to use that library to make > such a tool. This is even better as we can use klibc for it. Here is a update, which supports iso9660 and udf labels. Not very useful in the udev case, but I've added it for hal, so we just catch up with the latest version. --- extras/volume_id/volume_id.c | 672 ++++++++++++++++++++++++++--------- extras/volume_id/volume_id.h | 53 +-- 2 files changed, 525 insertions(+), 200 deletions(-) diff --git a/extras/volume_id/volume_id.c b/extras/volume_id/volume_id.c index cc5475fc8..8eba4b22f 100644 --- a/extras/volume_id/volume_id.c +++ b/extras/volume_id/volume_id.c @@ -11,19 +11,19 @@ * a look at: * http://e2fsprogs.sourceforge.net. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. + * 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 program 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * 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 @@ -38,6 +38,17 @@ #include "volume_id.h" +#ifdef DEBUG +#define dbg(format, arg...) \ + do { \ + printf("%s: " format "\n", __FUNCTION__ , ## arg); \ + } while (0) +#else +#define dbg(format, arg...) do {} while (0) +#endif + +#define bswap16(x) (__u16)((((__u16)(x) & 0x00ffu) << 8) | \ + (((__u32)(x) & 0xff00u) >> 8)) #define bswap32(x) (__u32)((((__u32)(x) & 0xff000000u) >> 24) | \ (((__u32)(x) & 0x00ff0000u) >> 8) | \ @@ -45,19 +56,28 @@ (((__u32)(x) & 0x000000ffu) << 24)) #if (__BYTE_ORDER == __LITTLE_ENDIAN) -#define cpu_to_le32(x) (x) +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) #elif (__BYTE_ORDER == __BIG_ENDIAN) -#define cpu_to_le32(x) bswap32(x) +#define le16_to_cpu(x) bswap16(x) +#define le32_to_cpu(x) bswap32(x) #endif -#define VOLUME_ID_BUFFER_SIZE 0x11000 /* reiser offset is 64k */ +/* size of superblock buffer, reiser block is at 64k */ +#define SB_BUFFER_SIZE 0x11000 +/* size of seek buffer 2k */ +#define SEEK_BUFFER_SIZE 0x800 -static void set_label(struct volume_id *id, char *buf, int count) +static void set_label_raw(struct volume_id *id, char *buf, int count) { - int i; + memcpy(id->label_raw, buf, count); + id->label_raw_len = count; +} - memcpy(id->label, buf, count); +static void set_label_string(struct volume_id *id, char *buf, int count) +{ + int i; memcpy(id->label_string, buf, count); @@ -90,7 +110,8 @@ set: break; case 16: sprintf(id->uuid_string, - "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + "%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], @@ -100,29 +121,67 @@ set: } } -static int open_superblock(struct volume_id *id) +static char *get_buffer(struct volume_id *id, size_t off, size_t len) { - /* get buffer to read the first block */ - if (id->buf == NULL) { - id->buf = malloc(VOLUME_ID_BUFFER_SIZE); - if (id->buf == NULL) - return -1; + size_t buf_len; + + /* check if requested area fits in superblock buffer */ + if (off + len <= SB_BUFFER_SIZE) { + if (id->sbbuf == NULL) { + id->sbbuf = malloc(SB_BUFFER_SIZE); + if (id->sbbuf == NULL) + return NULL; + } + + /* check if we need to read */ + if ((off + len) > id->sbbuf_len) { + dbg("read sbbuf len:0x%x", off + len); + lseek(id->fd, 0, SEEK_SET); + buf_len = read(id->fd, id->sbbuf, off + len); + id->sbbuf_len = buf_len; + if (buf_len < off + len) + return NULL; + } + + return &(id->sbbuf[off]); + } else { + if (len > SEEK_BUFFER_SIZE) + len = SEEK_BUFFER_SIZE; + + /* get seek buffer */ + if (id->seekbuf == NULL) { + id->seekbuf = malloc(SEEK_BUFFER_SIZE); + if (id->seekbuf == NULL) + return NULL; + } + + /* check if we need to read */ + if ((off < id->seekbuf_off) || + ((off + len) > (id->seekbuf_off + id->seekbuf_len))) { + dbg("read seekbuf off:0x%x len:0x%x", off, len); + lseek(id->fd, off, SEEK_SET); + buf_len = read(id->fd, id->seekbuf, len); + id->seekbuf_off = off; + id->seekbuf_len = buf_len; + if (buf_len < len) + return NULL; + } + + return &(id->seekbuf[off - id->seekbuf_off]); } - - /* try to read the first 64k, but at least the first block */ - memset(id->buf, 0x00, VOLUME_ID_BUFFER_SIZE); - lseek(id->fd, 0, SEEK_SET); - if (read(id->fd, id->buf, VOLUME_ID_BUFFER_SIZE) < 0x200) - return -1; - - return 0; } -static void close_superblock(struct volume_id *id) +static void free_buffer(struct volume_id *id) { - if (id->buf != NULL) { - free(id->buf); - id->buf = NULL; + if (id->sbbuf != NULL) { + free(id->sbbuf); + id->sbbuf = NULL; + id->sbbuf_len = 0; + } + if (id->seekbuf != NULL) { + free(id->seekbuf); + id->seekbuf = NULL; + id->seekbuf_len = 0; } } @@ -132,34 +191,39 @@ static void close_superblock(struct volume_id *id) static int probe_ext(struct volume_id *id) { struct ext2_super_block { - __u32 s_inodes_count; - __u32 s_blocks_count; - __u32 s_r_blocks_count; - __u32 s_free_blocks_count; - __u32 s_free_inodes_count; - __u32 s_first_data_block; - __u32 s_log_block_size; - __u32 s_dummy3[7]; - unsigned char s_magic[2]; - __u16 s_state; - __u32 s_dummy5[8]; - __u32 s_feature_compat; - __u32 s_feature_incompat; - __u32 s_feature_ro_compat; - unsigned char s_uuid[16]; - char s_volume_name[16]; + __u32 inodes_count; + __u32 blocks_count; + __u32 r_blocks_count; + __u32 free_blocks_count; + __u32 free_inodes_count; + __u32 first_data_block; + __u32 log_block_size; + __u32 dummy3[7]; + unsigned char magic[2]; + __u16 state; + __u32 dummy5[8]; + __u32 feature_compat; + __u32 feature_incompat; + __u32 feature_ro_compat; + unsigned char uuid[16]; + char volume_name[16]; } *es; - es = (struct ext2_super_block *) (id->buf + EXT_SUPERBLOCK_OFFSET); + es = (struct ext2_super_block *) + get_buffer(id, EXT_SUPERBLOCK_OFFSET, 0x200); + if (es == NULL) + return -1; - if (es->s_magic[0] != 0123 || - es->s_magic[1] != 0357) + if (es->magic[0] != 0123 || + es->magic[1] != 0357) return -1; - set_label(id, es->s_volume_name, 16); - set_uuid(id, es->s_uuid, 16); + set_label_raw(id, es->volume_name, 16); + set_label_string(id, es->volume_name, 16); + set_uuid(id, es->uuid, 16); - if ((cpu_to_le32(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) { + if ((le32_to_cpu(es->feature_compat) & + EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) { id->fs_type = EXT3; id->fs_name = "ext3"; } else { @@ -175,38 +239,45 @@ static int probe_ext(struct volume_id *id) static int probe_reiser(struct volume_id *id) { struct reiser_super_block { - __u32 rs_blocks_count; - __u32 rs_free_blocks; - __u32 rs_root_block; - __u32 rs_journal_block; - __u32 rs_journal_dev; - __u32 rs_orig_journal_size; - __u32 rs_dummy2[5]; - __u16 rs_blocksize; - __u16 rs_dummy3[3]; - unsigned char rs_magic[12]; - __u32 rs_dummy4[5]; - unsigned char rs_uuid[16]; - char rs_label[16]; + __u32 blocks_count; + __u32 free_blocks; + __u32 root_block; + __u32 journal_block; + __u32 journal_dev; + __u32 orig_journal_size; + __u32 dummy2[5]; + __u16 blocksize; + __u16 dummy3[3]; + unsigned char magic[12]; + __u32 dummy4[5]; + unsigned char uuid[16]; + char label[16]; } *rs; - rs = (struct reiser_super_block *) &(id->buf[REISER1_SUPERBLOCK_OFFSET]); + rs = (struct reiser_super_block *) + get_buffer(id, REISER_SUPERBLOCK_OFFSET, 0x200); + if (rs == NULL) + return -1; - if (strncmp(rs->rs_magic, "ReIsErFs", 8) == 0) + if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0) + goto found; + if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0) goto found; - rs = (struct reiser_super_block *) &(id->buf[REISER_SUPERBLOCK_OFFSET]); + rs = (struct reiser_super_block *) + get_buffer(id, REISER1_SUPERBLOCK_OFFSET, 0x200); + if (rs == NULL) + return -1; - if (strncmp(rs->rs_magic, "ReIsEr2Fs", 9) == 0) - goto found; - if (strncmp(rs->rs_magic, "ReIsEr3Fs", 9) == 0) + if (strncmp(rs->magic, "ReIsErFs", 8) == 0) goto found; return -1; found: - set_label(id, rs->rs_label, 16); - set_uuid(id, rs->rs_uuid, 16); + set_label_raw(id, rs->label, 16); + set_label_string(id, rs->label, 16); + set_uuid(id, rs->uuid, 16); id->fs_type = REISER; id->fs_name = "reiser"; @@ -217,27 +288,30 @@ found: static int probe_xfs(struct volume_id *id) { struct xfs_super_block { - unsigned char xs_magic[4]; - __u32 xs_blocksize; - __u64 xs_dblocks; - __u64 xs_rblocks; - __u32 xs_dummy1[2]; - unsigned char xs_uuid[16]; - __u32 xs_dummy2[15]; - char xs_fname[12]; - __u32 xs_dummy3[2]; - __u64 xs_icount; - __u64 xs_ifree; - __u64 xs_fdblocks; + unsigned char magic[4]; + __u32 blocksize; + __u64 dblocks; + __u64 rblocks; + __u32 dummy1[2]; + unsigned char uuid[16]; + __u32 dummy2[15]; + char fname[12]; + __u32 dummy3[2]; + __u64 icount; + __u64 ifree; + __u64 fdblocks; } *xs; - xs = (struct xfs_super_block *) id->buf; + xs = (struct xfs_super_block *) get_buffer(id, 0, 0x200); + if (xs == NULL) + return -1; - if (strncmp(xs->xs_magic, "XFSB", 4) != 0) + if (strncmp(xs->magic, "XFSB", 4) != 0) return -1; - set_label(id, xs->xs_fname, 12); - set_uuid(id, xs->xs_uuid, 16); + set_label_raw(id, xs->fname, 12); + set_label_string(id, xs->fname, 12); + set_uuid(id, xs->uuid, 16); id->fs_type = XFS; id->fs_name = "xfs"; @@ -249,25 +323,29 @@ static int probe_xfs(struct volume_id *id) static int probe_jfs(struct volume_id *id) { struct jfs_super_block { - unsigned char js_magic[4]; - __u32 js_version; - __u64 js_size; - __u32 js_bsize; - __u32 js_dummy1; - __u32 js_pbsize; - __u32 js_dummy2[27]; - unsigned char js_uuid[16]; - unsigned char js_label[16]; - unsigned char js_loguuid[16]; + unsigned char magic[4]; + __u32 version; + __u64 size; + __u32 bsize; + __u32 dummy1; + __u32 pbsize; + __u32 dummy2[27]; + unsigned char uuid[16]; + unsigned char label[16]; + unsigned char loguuid[16]; } *js; - js = (struct jfs_super_block *) &(id->buf[JFS_SUPERBLOCK_OFFSET]); + js = (struct jfs_super_block *) + get_buffer(id, JFS_SUPERBLOCK_OFFSET, 0x200); + if (js == NULL) + return -1; - if (strncmp(js->js_magic, "JFS1", 4) != 0) + if (strncmp(js->magic, "JFS1", 4) != 0) return -1; - set_label(id, js->js_label, 16); - set_uuid(id, js->js_uuid, 16); + set_label_raw(id, js->label, 16); + set_label_string(id, js->label, 16); + set_uuid(id, js->uuid, 16); id->fs_type = JFS; id->fs_name = "jfs"; @@ -278,46 +356,49 @@ static int probe_jfs(struct volume_id *id) static int probe_vfat(struct volume_id *id) { struct vfat_super_block { - unsigned char vs_ignored[3]; - unsigned char vs_sysid[8]; - unsigned char vs_sector_size[2]; - __u8 vs_cluster_size; - __u16 vs_reserved; - __u8 vs_fats; - unsigned char vs_dir_entries[2]; - unsigned char vs_sectors[2]; - unsigned char vs_media; - __u16 vs_fat_length; - __u16 vs_secs_track; - __u16 vs_heads; - __u32 vs_hidden; - __u32 vs_total_sect; - __u32 vs_fat32_length; - __u16 vs_flags; - __u8 vs_version[2]; - __u32 vs_root_cluster; - __u16 vs_insfo_sector; - __u16 vs_backup_boot; - __u16 vs_reserved2[6]; - unsigned char vs_unknown[3]; - unsigned char vs_serno[4]; - char vs_label[11]; - unsigned char vs_magic[8]; - unsigned char vs_dummy2[164]; - unsigned char vs_pmagic[2]; + unsigned char ignored[3]; + unsigned char sysid[8]; + unsigned char sector_size[2]; + __u8 cluster_size; + __u16 reserved; + __u8 fats; + unsigned char dir_entries[2]; + unsigned char sectors[2]; + unsigned char media; + __u16 fat_length; + __u16 secs_track; + __u16 heads; + __u32 hidden; + __u32 total_sect; + __u32 fat32_length; + __u16 flags; + __u8 version[2]; + __u32 root_cluster; + __u16 insfo_sector; + __u16 backup_boot; + __u16 reserved2[6]; + unsigned char unknown[3]; + unsigned char serno[4]; + char label[11]; + unsigned char magic[8]; + unsigned char dummy2[164]; + unsigned char pmagic[2]; } *vs; - vs = (struct vfat_super_block *) id->buf; + vs = (struct vfat_super_block *) get_buffer(id, 0, 0x200); + if (vs == NULL) + return -1; - if (strncmp(vs->vs_magic, "MSWIN", 5) == 0) + if (strncmp(vs->magic, "MSWIN", 5) == 0) goto found; - if (strncmp(vs->vs_magic, "FAT32 ", 8) == 0) + if (strncmp(vs->magic, "FAT32 ", 8) == 0) goto found; return -1; found: - memcpy(id->label, vs->vs_label, 11); - memcpy(id->uuid, vs->vs_serno, 4); + set_label_raw(id, vs->label, 11); + set_label_string(id, vs->label, 11); + set_uuid(id, vs->serno, 4); id->fs_type = VFAT; id->fs_name = "vfat"; @@ -328,41 +409,44 @@ found: static int probe_msdos(struct volume_id *id) { struct msdos_super_block { - unsigned char ms_ignored[3]; - unsigned char ms_sysid[8]; - unsigned char ms_sector_size[2]; - __u8 ms_cluster_size; - __u16 ms_reserved; - __u8 ms_fats; - unsigned char ms_dir_entries[2]; - unsigned char ms_sectors[2]; - unsigned char ms_media; - __u16 ms_fat_length; - __u16 ms_secs_track; - __u16 ms_heads; - __u32 ms_hidden; - __u32 ms_total_sect; - unsigned char ms_unknown[3]; - unsigned char ms_serno[4]; - char ms_label[11]; - unsigned char ms_magic[8]; - unsigned char ms_dummy2[192]; - unsigned char ms_pmagic[2]; + unsigned char ignored[3]; + unsigned char sysid[8]; + unsigned char sector_size[2]; + __u8 cluster_size; + __u16 reserved; + __u8 fats; + unsigned char dir_entries[2]; + unsigned char sectors[2]; + unsigned char media; + __u16 fat_length; + __u16 secs_track; + __u16 heads; + __u32 hidden; + __u32 total_sect; + unsigned char unknown[3]; + unsigned char serno[4]; + char label[11]; + unsigned char magic[8]; + unsigned char dummy2[192]; + unsigned char pmagic[2]; } *ms; - ms = (struct msdos_super_block *) id->buf; + ms = (struct msdos_super_block *) get_buffer(id, 0, 0x200); + if (ms == NULL) + return -1; - if (strncmp(ms->ms_magic, "MSDOS", 5) == 0) + if (strncmp(ms->magic, "MSDOS", 5) == 0) goto found; - if (strncmp(ms->ms_magic, "FAT16 ", 8) == 0) + if (strncmp(ms->magic, "FAT16 ", 8) == 0) goto found; - if (strncmp(ms->ms_magic, "FAT12 ", 8) == 0) + if (strncmp(ms->magic, "FAT12 ", 8) == 0) goto found; return -1; found: - set_label(id, ms->ms_label, 11); - set_uuid(id, ms->ms_serno, 4); + set_label_raw(id, ms->label, 11); + set_label_string(id, ms->label, 11); + set_uuid(id, ms->serno, 4); id->fs_type = MSDOS; id->fs_name = "msdos"; @@ -370,6 +454,218 @@ found: return 0; } +#define UDF_VSD_OFFSET 0x8000 +static int probe_udf(struct volume_id *id) +{ + struct volume_descriptor { + struct descriptor_tag { + __u16 id; + __u16 version; + unsigned char checksum; + unsigned char reserved; + __u16 serial; + __u16 crc; + __u16 crc_len; + __u32 location; + } tag; + union { + struct anchor_descriptor { + __u32 length; + __u32 location; + } anchor; + struct primary_descriptor { + __u32 seq_num; + __u32 desc_num; + struct dstring { + char clen; + char c[31]; + } ident; + } primary; + } type; + } *vd; + + struct volume_structure_descriptor { + unsigned char type; + char id[5]; + unsigned char version; + } *vsd; + + size_t bs; + size_t b; + int type; + int count; + int loc; + int clen; + int i,j; + int c; + + vsd = (struct volume_structure_descriptor *) + get_buffer(id, UDF_VSD_OFFSET, 0x200); + if (vsd == NULL) + return -1; + + if (strncmp(vsd->id, "NSR02", 5) == 0) + goto blocksize; + if (strncmp(vsd->id, "NSR03", 5) == 0) + goto blocksize; + if (strncmp(vsd->id, "BEA01", 5) == 0) + goto blocksize; + if (strncmp(vsd->id, "BOOT2", 5) == 0) + goto blocksize; + if (strncmp(vsd->id, "CD001", 5) == 0) + goto blocksize; + if (strncmp(vsd->id, "CDW02", 5) == 0) + goto blocksize; + if (strncmp(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 = (struct volume_structure_descriptor *) + get_buffer(id, 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 = (struct volume_structure_descriptor *) + get_buffer(id, 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 (strncmp(vsd->id, "NSR02", 5) == 0) + goto anchor; + if (strncmp(vsd->id, "NSR03", 5) == 0) + goto anchor; + } + return -1; + +anchor: + /* read anchor volume descriptor */ + vd = (struct volume_descriptor *) get_buffer(id, 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 = (struct volume_descriptor *) + get_buffer(id, (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: + 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) { + set_label_string(id, vd->type.primary.ident.c, 31); + } else if (clen == 16) { + /* convert unicode OSTA dstring to UTF-8 */ + j = 0; + for (i = 0; i < 32; i += 2) { + c = (vd->type.primary.ident.c[i] << 8) | + vd->type.primary.ident.c[i+1]; + if (c == 0) { + id->label_string[j] = '\0'; + break; + }else if (c < 0x80U) { + id->label_string[j++] = (char) c; + } else if (c < 0x800U) { + id->label_string[j++] = (char) (0xc0 | (c >> 6)); + id->label_string[j++] = (char) (0x80 | (c & 0x3f)); + } else { + id->label_string[j++] = (char) (0xe0 | (c >> 12)); + id->label_string[j++] = (char) (0x80 | ((c >> 6) & 0x3f)); + id->label_string[j++] = (char) (0x80 | (c & 0x3f)); + } + } + } + +found: + id->fs_type = UDF; + id->fs_name = "udf"; + + return 0; +} + +#define ISO_SUPERBLOCK_OFFSET 0x8000 +static int probe_iso9660(struct volume_id *id) +{ + union iso_super_block { + struct iso_header { + unsigned char type; + char id[5]; + unsigned char version; + unsigned char unused1; + char system_id[32]; + char volume_id[32]; + } iso; + struct hs_header { + char foo[8]; + unsigned char type; + char id[4]; + unsigned char version; + } hs; + } *is; + + is = (union iso_super_block *) + get_buffer(id, ISO_SUPERBLOCK_OFFSET, 0x200); + if (is == NULL) + return -1; + + if (strncmp(is->iso.id, "CD001", 5) == 0) { + set_label_raw(id, is->iso.volume_id, 32); + set_label_string(id, is->iso.volume_id, 32); + goto found; + } + if (strncmp(is->hs.id, "CDROM", 5) == 0) + goto found; + return -1; + +found: + id->fs_type = ISO9660; + id->fs_name = "iso9660"; + + return 0; +} + static int probe_ntfs(struct volume_id *id) { struct ntfs_super_block { @@ -377,7 +673,9 @@ static int probe_ntfs(struct volume_id *id) char oem_id[4]; } *ns; - ns = (struct ntfs_super_block *) id->buf; + ns = (struct ntfs_super_block *) get_buffer(id, 0, 0x200); + if (ns == NULL) + return -1; if (strncmp(ns->oem_id, "NTFS", 4) != 0) return -1; @@ -388,15 +686,21 @@ static int probe_ntfs(struct volume_id *id) return 0; } +#define LARGEST_PAGESIZE 0x4000 static int probe_swap(struct volume_id *id) { - int magic; + char *sig; + size_t page; /* huhh, the swap signature is on the end of the PAGE_SIZE */ - for (magic = 0x1000; magic <= 0x4000; magic <<= 1) { - if (strncmp(&(id->buf[magic -10]), "SWAP-SPACE", 10) == 0) + for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) { + sig = get_buffer(id, page-10, 10); + if (sig == NULL) + return -1; + + if (strncmp(sig, "SWAP-SPACE", 10) == 0) goto found; - if (strncmp(&(id->buf[magic -10]), "SWAPSPACE2", 10) == 0) + if (strncmp(sig, "SWAPSPACE2", 10) == 0) goto found; } return -1; @@ -416,9 +720,6 @@ int volume_id_probe(struct volume_id *id, enum filesystem_type fs_type) if (id == NULL) return -EINVAL; - if (open_superblock(id) != 0) - return -EACCES; - switch (fs_type) { case EXT3: case EXT2: @@ -439,13 +740,22 @@ int volume_id_probe(struct volume_id *id, enum filesystem_type fs_type) case VFAT: rc = probe_vfat(id); break; + case UDF: + rc = probe_udf(id); + break; + case ISO9660: + rc = probe_iso9660(id); + break; case NTFS: rc = probe_ntfs(id); break; case SWAP: rc = probe_swap(id); break; + case ALL: default: + /* fill buffer with maximum */ + get_buffer(id, 0, SB_BUFFER_SIZE); rc = probe_ext(id); if (rc == 0) break; @@ -462,6 +772,12 @@ int volume_id_probe(struct volume_id *id, enum filesystem_type fs_type) if (rc == 0) break; rc = probe_vfat(id); + if (rc == 0) + break; + rc = probe_udf(id); + if (rc == 0) + break; + rc = probe_iso9660(id); if (rc == 0) break; rc = probe_ntfs(id); @@ -473,8 +789,10 @@ int volume_id_probe(struct volume_id *id, enum filesystem_type fs_type) rc = -1; } + /* If the filestystem in recognized, we free the allocated buffers, + otherwise they will stay in place for the possible next probe call */ if (rc == 0) - close_superblock(id); + free_buffer(id); return rc; } @@ -544,7 +862,7 @@ void volume_id_close(struct volume_id *id) if (id->fd_close != 0) close(id->fd); - close_superblock(id); + free_buffer(id); free(id); } diff --git a/extras/volume_id/volume_id.h b/extras/volume_id/volume_id.h index a0d2acda2..2f20244c7 100644 --- a/extras/volume_id/volume_id.h +++ b/extras/volume_id/volume_id.h @@ -3,27 +3,27 @@ * * Copyright (C) 2004 Kay Sievers * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - * - * This program 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * 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 */ #ifndef _VOLUME_ID_H_ #define _VOLUME_ID_H_ -#define VOLUME_ID_VERSION 001 +#define VOLUME_ID_VERSION 002 -#define VOLUME_ID_LABEL_SIZE 16 +#define VOLUME_ID_LABEL_SIZE 32 #define VOLUME_ID_UUID_SIZE 16 #define VOLUME_ID_UUID_STRING_SIZE 37 #define VOLUME_ID_PATH_MAX 255 @@ -38,20 +38,27 @@ enum filesystem_type { JFS, MSDOS, VFAT, + UDF, + ISO9660, NTFS, SWAP }; struct volume_id { - char label[VOLUME_ID_LABEL_SIZE]; - char label_string[VOLUME_ID_LABEL_SIZE+1]; - unsigned char uuid[VOLUME_ID_UUID_SIZE]; - char uuid_string[VOLUME_ID_UUID_STRING_SIZE]; - enum filesystem_type fs_type; - char *fs_name; - int fd; - char *buf; - int fd_close; + char label_raw[VOLUME_ID_LABEL_SIZE]; + size_t label_raw_len; + char label_string[VOLUME_ID_LABEL_SIZE+1]; + unsigned char uuid[VOLUME_ID_UUID_SIZE]; + char uuid_string[VOLUME_ID_UUID_STRING_SIZE]; + enum filesystem_type fs_type; + char *fs_name; + int fd; + char *sbbuf; + size_t sbbuf_len; + char *seekbuf; + size_t seekbuf_off; + size_t seekbuf_len; + int fd_close; }; /* open volume by already open file descriptor */ -- 2.30.2