diff options
Diffstat (limited to 'shlibs/blkid/src')
26 files changed, 730 insertions, 196 deletions
diff --git a/shlibs/blkid/src/Makefile.am b/shlibs/blkid/src/Makefile.am index 90ce9bfc..2d798b6a 100644 --- a/shlibs/blkid/src/Makefile.am +++ b/shlibs/blkid/src/Makefile.am @@ -25,7 +25,7 @@ usrlib_exec_LTLIBRARIES = libblkid.la libblkid_la_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c \ probe.c read.c resolve.c save.c tag.c version.c verify.c \ encode.c list.h blkidP.h superblocks/superblocks.h \ - config.c evaluate.c \ + config.c evaluate.c fat.h \ $(blkidinc_HEADERS) \ $(top_srcdir)/lib/blkdev.c \ $(top_srcdir)/lib/linux_version.c \ diff --git a/shlibs/blkid/src/blkid.h.in b/shlibs/blkid/src/blkid.h.in index febb4372..4e53b39f 100644 --- a/shlibs/blkid/src/blkid.h.in +++ b/shlibs/blkid/src/blkid.h.in @@ -142,6 +142,7 @@ extern int blkid_devno_to_wholedisk(dev_t dev, char *diskname, /* devname.c */ extern int blkid_probe_all(blkid_cache cache); extern int blkid_probe_all_new(blkid_cache cache); +extern int blkid_probe_all_removable(blkid_cache cache); extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags); diff --git a/shlibs/blkid/src/blkid.sym b/shlibs/blkid/src/blkid.sym index 97255526..4d01aa20 100644 --- a/shlibs/blkid/src/blkid.sym +++ b/shlibs/blkid/src/blkid.sym @@ -114,3 +114,11 @@ global: blkid_topology_get_optimal_io_size; blkid_topology_get_physical_sector_size; } BLKID_2.15; + +/* + * version(s) since util-linux-ng 2.18 + */ +BLKID_2.18 { +global: + blkid_probe_all_removable; +} BLKID_2.17; diff --git a/shlibs/blkid/src/blkidP.h b/shlibs/blkid/src/blkidP.h index 90900e27..d15b5305 100644 --- a/shlibs/blkid/src/blkidP.h +++ b/shlibs/blkid/src/blkidP.h @@ -51,6 +51,7 @@ struct blkid_struct_dev #define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */ #define BLKID_BID_FL_INVALID 0x0004 /* Device is invalid */ +#define BLKID_BID_FL_REMOVABLE 0x0008 /* Device added by blkid_probe_all_removable() */ /* * Each tag defines a NAME=value pair for a particular device. The tags @@ -133,8 +134,6 @@ struct blkid_prval struct blkid_chain *chain; /* owner */ }; -#define BLKID_SB_BUFSIZ 0x11000 - /* * Filesystem / Raid magic strings */ @@ -155,6 +154,7 @@ struct blkid_idinfo const char *name; /* fs, raid or partition table name */ int usage; /* BLKID_USAGE_* flag */ int flags; /* BLKID_IDINFO_* flags */ + int minsz; /* minimal device size */ /* probe function */ int (*probefunc)(blkid_probe pr, const struct blkid_idmag *mag); @@ -171,6 +171,13 @@ struct blkid_idinfo */ #define BLKID_IDINFO_TOLERANT (1 << 1) +struct blkid_bufinfo { + unsigned char *data; + blkid_loff_t off; + blkid_loff_t len; + struct list_head bufs; /* list of buffers */ +}; + /* * Low-level probing control struct */ @@ -186,13 +193,7 @@ struct blkid_struct_probe int flags; /* private libray flags */ - unsigned char *sbbuf; /* superblok buffer */ - size_t sbbuf_len; /* size of data in superblock buffer */ - - unsigned char *buf; /* seek buffer */ - blkid_loff_t buf_off; /* offset of seek buffer */ - size_t buf_len; /* size of data in seek buffer */ - size_t buf_max; /* allocated size of seek buffer */ + struct list_head buffers; /* list of buffers */ struct blkid_chain chains[BLKID_NCHAINS]; /* array of chains */ struct blkid_chain *cur_chain; /* current chain */ @@ -203,6 +204,7 @@ struct blkid_struct_probe /* flags */ #define BLKID_PRIVATE_FD (1 << 1) /* see blkid_new_probe_from_filename() */ +#define BLKID_TINY_DEV (1 << 2) /* <= 1.47MiB (floppy or so) */ /* * Evaluation methods (for blkid_eval_* API) @@ -266,6 +268,8 @@ extern char *blkid_strndup(const char *s, const int length); extern char *blkid_strconcat(const char *a, const char *b, const char *c); extern int blkid_fstatat(DIR *dir, const char *dirname, const char *filename, struct stat *st, int nofollow); +extern int blkid_openat(DIR *dir, const char *dirname, const char *filename, + int flags); #define BLKID_CACHE_FILE "/etc/blkid.tab" #define BLKID_CONFIG_FILE "/etc/blkid.conf" @@ -357,7 +361,8 @@ extern blkid_dev blkid_new_dev(void); extern void blkid_free_dev(blkid_dev dev); /* probe.c */ -unsigned char *blkid_probe_get_buffer(blkid_probe pr, +extern int blkid_probe_is_tiny(blkid_probe pr); +extern unsigned char *blkid_probe_get_buffer(blkid_probe pr, blkid_loff_t off, blkid_loff_t len); extern unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector); diff --git a/shlibs/blkid/src/devname.c b/shlibs/blkid/src/devname.c index d048c722..5d6da891 100644 --- a/shlibs/blkid/src/devname.c +++ b/shlibs/blkid/src/devname.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <fcntl.h> #if HAVE_SYS_TYPES_H #include <sys/types.h> #endif @@ -38,7 +39,9 @@ #include <time.h> #include "blkidP.h" + #include "canonicalize.h" /* $(top_srcdir)/include */ +#include "pathnames.h" /* * Find a dev struct in the cache by device name, if available. @@ -157,7 +160,7 @@ static int is_dm_leaf(const char *devname) * Probe a single block device to add to the device cache. */ static void probe_one(blkid_cache cache, const char *ptname, - dev_t devno, int pri, int only_if_new) + dev_t devno, int pri, int only_if_new, int removable) { blkid_dev dev = NULL; struct list_head *p, *pnext; @@ -237,6 +240,8 @@ set_pri: dev->bid_pri += 5; } else if (!strncmp(ptname, "md", 2)) dev->bid_pri = BLKID_PRI_MD; + if (removable) + dev->bid_flags |= BLKID_BID_FL_REMOVABLE; } return; } @@ -328,7 +333,7 @@ static void lvm_probe_all(blkid_cache cache, int only_if_new) lvm_device, (unsigned int) dev)); probe_one(cache, lvm_device, dev, BLKID_PRI_LVM, - only_if_new); + only_if_new, 0); free(lvm_device); } closedir(lv_list); @@ -360,7 +365,7 @@ evms_probe_all(blkid_cache cache, int only_if_new) device, ma, mi)); probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS, - only_if_new); + only_if_new, 0); num++; } fclose(procpt); @@ -408,7 +413,7 @@ ubi_probe_all(blkid_cache cache, int only_if_new) continue; DBG(DEBUG_DEVNAME, printf("UBI vol %s/%s: devno 0x%04X\n", *dirname, name, (int) dev)); - probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new); + probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new, 0); } closedir(dir); } @@ -485,7 +490,7 @@ static int probe_all(blkid_cache cache, int only_if_new) if (sz > 1) probe_one(cache, ptname, devs[which], 0, - only_if_new); + only_if_new, 0); lens[which] = 0; /* mark as checked */ } @@ -522,20 +527,81 @@ static int probe_all(blkid_cache cache, int only_if_new) printf("whole dev %s, devno 0x%04X\n", ptnames[last], (unsigned int) devs[last])); probe_one(cache, ptnames[last], devs[last], 0, - only_if_new); + only_if_new, 0); lens[last] = 0; } } /* Handle the last device if it wasn't partitioned */ if (lens[which]) - probe_one(cache, ptname, devs[which], 0, only_if_new); + probe_one(cache, ptname, devs[which], 0, only_if_new, 0); fclose(proc); blkid_flush_cache(cache); return 0; } +/* Don't use it by default -- it's pretty slow (because cdroms, floppy, ...) + */ +static int probe_all_removable(blkid_cache cache) +{ + DIR *dir; + struct dirent *d; + char buf[PATH_MAX]; + + if (!cache) + return -BLKID_ERR_PARAM; + + dir = opendir(_PATH_SYS_BLOCK); + if (!dir) + return -BLKID_ERR_PROC; + + while((d = readdir(dir))) { + int fd, rc, ma, mi; + +#ifdef _DIRENT_HAVE_D_TYPE + if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK) + continue; +#endif + if (d->d_name[0] == '.' && + ((d->d_name[1] == 0) || + ((d->d_name[1] == '.') && (d->d_name[2] == 0)))) + continue; + + snprintf(buf, sizeof(buf), "%s/removable", d->d_name); + fd = blkid_openat(dir, _PATH_SYS_BLOCK, buf, O_RDONLY); + if (fd < 0) + continue; + + rc = read(fd, buf, 1); + close(fd); + + if (rc != 1 || *buf != '1') + continue; /* not removable device */ + + /* get devno */ + snprintf(buf, sizeof(buf), "%s/dev", d->d_name); + fd = blkid_openat(dir, _PATH_SYS_BLOCK, buf, O_RDONLY); + if (fd < 0) + continue; + + rc = read(fd, buf, sizeof(buf)); + close(fd); + + if (rc < 3) + continue; /* M:N */ + buf[rc] = '\0'; + if (sscanf(buf, "%d:%d", &ma, &mi) != 2) + continue; + + probe_one(cache, d->d_name, makedev(ma, mi), 0, 0, 1); + } + + closedir(dir); + return 0; +} + + /** * blkid_probe_all: * @cache: cache handler @@ -574,6 +640,33 @@ int blkid_probe_all_new(blkid_cache cache) return ret; } +/** + * blkid_probe_all_removable: + * @cache: cache handler + * + * The libblkid probing is based on devices from /proc/partitions by default. + * This file usually does not contain removable devices (e.g. CDROMs) and this kind + * of devices are invisible for libblkid. + * + * This function adds removable block devices to @cache (probing is based on + * information from the /sys directory). Don't forget that removable devices + * (floppies, CDROMs, ...) could be pretty slow. It's very bad idea to call + * this function by default. + * + * Note that devices which were detected by this function won't be written to + * blkid.tab cache file. + * + * Returns: 0 on success, or number less than zero in case of error. + */ +int blkid_probe_all_removable(blkid_cache cache) +{ + int ret; + + DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_removable()\n")); + ret = probe_all_removable(cache); + DBG(DEBUG_PROBE, printf("End blkid_probe_all_removable()\n")); + return ret; +} #ifdef TEST_PROGRAM int main(int argc, char **argv) @@ -595,6 +688,9 @@ int main(int argc, char **argv) if (blkid_probe_all(cache) < 0) printf("%s: error probing devices\n", argv[0]); + if (blkid_probe_all_removable(cache) < 0) + printf("%s: error probing removable devices\n", argv[0]); + blkid_put_cache(cache); return (0); } diff --git a/shlibs/blkid/src/devno.c b/shlibs/blkid/src/devno.c index 7b9438ff..284f8733 100644 --- a/shlibs/blkid/src/devno.c +++ b/shlibs/blkid/src/devno.c @@ -96,14 +96,30 @@ int blkid_fstatat(DIR *dir, const char *dirname, const char *filename, return fstatat(dirfd(dir), filename, st, nofollow ? AT_SYMLINK_NOFOLLOW : 0); #else - char device[PATH_MAX]; + char path[PATH_MAX]; + int len; + + len = snprintf(path, sizeof(path), "%s/%s", dirname, filename); + if (len < 0 || len + 1 > sizeof(path)) + return -1; + + return nofollow ? lstat(path, st) : stat(path, st); +#endif +} + +int blkid_openat(DIR *dir, const char *dirname, const char *filename, int flags) +{ +#ifdef HAVE_FSTATAT + return openat(dirfd(dir), filename, flags); +#else + char path[PATH_MAX]; int len; - len = snprintf(device, sizeof(device), "%s/%s", dirname, filename); - if (len < 0 || len + 1 > sizeof(device)) + len = snprintf(path, sizeof(path), "%s/%s", dirname, filename); + if (len < 0 || len + 1 > sizeof(path)) return -1; - return nofollow ? lstat(device, st) : stat(device, st); + return open(path, flags); #endif } diff --git a/shlibs/blkid/src/fat.h b/shlibs/blkid/src/fat.h new file mode 100644 index 00000000..b3664641 --- /dev/null +++ b/shlibs/blkid/src/fat.h @@ -0,0 +1,90 @@ +#ifndef _BLKID_FAT_H +#define _BLKID_FAT_H + +/* This FAT superblock is required for: + * + * superblocks/vfat.c + * partitions/dos.c + */ + +/* Yucky misaligned values */ +struct vfat_super_block { +/* 00*/ unsigned char vs_ignored[3]; +/* 03*/ unsigned char vs_sysid[8]; +/* 0b*/ unsigned char vs_sector_size[2]; +/* 0d*/ uint8_t vs_cluster_size; +/* 0e*/ uint16_t vs_reserved; +/* 10*/ uint8_t vs_fats; +/* 11*/ unsigned char vs_dir_entries[2]; +/* 13*/ unsigned char vs_sectors[2]; +/* 15*/ unsigned char vs_media; +/* 16*/ uint16_t vs_fat_length; +/* 18*/ uint16_t vs_secs_track; +/* 1a*/ uint16_t vs_heads; +/* 1c*/ uint32_t vs_hidden; +/* 20*/ uint32_t vs_total_sect; +/* 24*/ uint32_t vs_fat32_length; +/* 28*/ uint16_t vs_flags; +/* 2a*/ uint8_t vs_version[2]; +/* 2c*/ uint32_t vs_root_cluster; +/* 30*/ uint16_t vs_fsinfo_sector; +/* 32*/ uint16_t vs_backup_boot; +/* 34*/ uint16_t vs_reserved2[6]; +/* 40*/ unsigned char vs_unknown[3]; +/* 43*/ unsigned char vs_serno[4]; +/* 47*/ unsigned char vs_label[11]; +/* 52*/ unsigned char vs_magic[8]; +/* 5a*/ unsigned char vs_dummy2[0x1fe - 0x5a]; +/*1fe*/ unsigned char vs_pmagic[2]; +} __attribute__((packed)); + +/* Yucky misaligned values */ +struct msdos_super_block { +/* 00*/ unsigned char ms_ignored[3]; +/* 03*/ unsigned char ms_sysid[8]; +/* 0b*/ unsigned char ms_sector_size[2]; +/* 0d*/ uint8_t ms_cluster_size; +/* 0e*/ uint16_t ms_reserved; +/* 10*/ uint8_t ms_fats; +/* 11*/ unsigned char ms_dir_entries[2]; +/* 13*/ unsigned char ms_sectors[2]; /* =0 iff V3 or later */ +/* 15*/ unsigned char ms_media; +/* 16*/ uint16_t ms_fat_length; /* Sectors per FAT */ +/* 18*/ uint16_t ms_secs_track; +/* 1a*/ uint16_t ms_heads; +/* 1c*/ uint32_t ms_hidden; +/* V3 BPB */ +/* 20*/ uint32_t ms_total_sect; /* iff ms_sectors == 0 */ +/* V4 BPB */ +/* 24*/ unsigned char ms_unknown[3]; /* Phys drive no., resvd, V4 sig (0x29) */ +/* 27*/ unsigned char ms_serno[4]; +/* 2b*/ unsigned char ms_label[11]; +/* 36*/ unsigned char ms_magic[8]; +/* 3e*/ unsigned char ms_dummy2[0x1fe - 0x3e]; +/*1fe*/ unsigned char ms_pmagic[2]; +} __attribute__((packed)); + + +static inline int blkid_fat_valid_media(struct msdos_super_block *ms) +{ + return 0xf8 <= ms->ms_media || ms->ms_media == 0xf0; +} + +static inline int blkid_fat_valid_sectorsize( + struct msdos_super_block *ms, + uint16_t *sector_size) +{ + unsigned char *tmp = (unsigned char *) &ms->ms_sector_size; + uint16_t ssz; + + ssz = tmp[0] + (tmp[1] << 8); + + if (ssz != 0x200 && ssz != 0x400 && ssz != 0x800 && ssz != 0x1000) + return 0; + if (sector_size) + *sector_size = ssz; + return 1; +} + + +#endif /* _BLKID_FAT_H */ diff --git a/shlibs/blkid/src/partitions/dos.c b/shlibs/blkid/src/partitions/dos.c index 21728a5a..ec2ca1eb 100644 --- a/shlibs/blkid/src/partitions/dos.c +++ b/shlibs/blkid/src/partitions/dos.c @@ -16,6 +16,7 @@ #include "partitions.h" #include "dos.h" #include "aix.h" +#include "fat.h" static const struct dos_subtypes { unsigned char type; @@ -139,18 +140,30 @@ static int probe_dos_pt(blkid_probe pr, const struct blkid_idmag *mag) if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0) goto nothing; - p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); - /* * Now that the 55aa signature is present, this is probably * either the boot sector of a FAT filesystem or a DOS-type - * partition table. Reject this in case the boot indicator - * is not 0 or 0x80. + * partition table. */ - for (p = p0, i = 0; i < 4; i++, p++) { + { + struct msdos_super_block *ms = + (struct msdos_super_block *) data; + + if (ms->ms_fats && ms->ms_reserved && + ms->ms_cluster_size && + blkid_fat_valid_media(ms) && + blkid_fat_valid_sectorsize(ms, NULL)) + goto nothing; /* FAT */ + } + + p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); + + /* + * Reject PT where boot indicator is not 0 or 0x80. + */ + for (p = p0, i = 0; i < 4; i++, p++) if (p->boot_ind != 0 && p->boot_ind != 0x80) goto nothing; - } /* * GPT uses valid MBR diff --git a/shlibs/blkid/src/partitions/gpt.c b/shlibs/blkid/src/partitions/gpt.c index 2ec3f739..2c3a3267 100644 --- a/shlibs/blkid/src/partitions/gpt.c +++ b/shlibs/blkid/src/partitions/gpt.c @@ -368,6 +368,7 @@ const struct blkid_idinfo gpt_pt_idinfo = { .name = "gpt", .probefunc = probe_gpt_pt, + .minsz = 1024 * 1440 + 1, /* ignore floppies */ /* * It would be possible to check for DOS signature (0xAA55), but diff --git a/shlibs/blkid/src/partitions/partitions.c b/shlibs/blkid/src/partitions/partitions.c index 82861a5b..154365d7 100644 --- a/shlibs/blkid/src/partitions/partitions.c +++ b/shlibs/blkid/src/partitions/partitions.c @@ -505,6 +505,9 @@ static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id) int hasmag = 0; int rc = 1; /* = nothing detected */ + if (id->minsz && id->minsz > pr->size) + goto nothing; /* the device is too small */ + mag = id->magics ? &id->magics[0] : NULL; /* try to detect by magic string */ diff --git a/shlibs/blkid/src/partitions/unixware.c b/shlibs/blkid/src/partitions/unixware.c index 70b6626f..62dba764 100644 --- a/shlibs/blkid/src/partitions/unixware.c +++ b/shlibs/blkid/src/partitions/unixware.c @@ -173,6 +173,7 @@ const struct blkid_idinfo unixware_pt_idinfo = { .name = "unixware", .probefunc = probe_unixware_pt, + .minsz = 1024 * 1440 + 1, /* ignore floppies */ .magics = { { diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c index 7ed80072..91366851 100644 --- a/shlibs/blkid/src/probe.c +++ b/shlibs/blkid/src/probe.c @@ -115,6 +115,7 @@ static const struct blkid_chaindrv *chains_drvs[] = { }; static void blkid_probe_reset_vals(blkid_probe pr); +static void blkid_probe_reset_buffer(blkid_probe pr); /** * blkid_new_probe: @@ -137,6 +138,7 @@ blkid_probe blkid_new_probe(void) pr->chains[i].flags = chains_drvs[i]->dflt_flags; pr->chains[i].enabled = chains_drvs[i]->dflt_enabled; } + INIT_LIST_HEAD(&pr->buffers); return pr; } @@ -202,26 +204,13 @@ void blkid_free_probe(blkid_probe pr) ch->driver->free_data(pr, ch->data); free(ch->fltr); } - free(pr->buf); - free(pr->sbbuf); if ((pr->flags & BLKID_PRIVATE_FD) && pr->fd >= 0) close(pr->fd); + blkid_probe_reset_buffer(pr); free(pr); } -static void blkid_probe_reset_buffer(blkid_probe pr) -{ - DBG(DEBUG_LOWPROBE, printf("reseting blkid probe buffer\n")); - if (pr->buf) - memset(pr->buf, 0, pr->buf_max); - pr->buf_off = 0; - pr->buf_len = 0; - if (pr->sbbuf) - memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ); - pr->sbbuf_len = 0; -} - /* * Removes chain values from probing result. @@ -470,73 +459,87 @@ int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[ return 0; } -/* - * Note that we have two offsets: - * - * 1/ general device offset (pr->off), that's useful for example when we - * probe a partition from whole disk image: - * blkid-low --offset <partition_position> disk.img - * - * 2/ buffer offset (the 'off' argument), that useful for offsets in - * superbloks, ... - * - * That means never use lseek(fd, 0, SEEK_SET), the zero position is always - * pr->off, so lseek(fd, pr->off, SEEK_SET). - * - */ unsigned char *blkid_probe_get_buffer(blkid_probe pr, blkid_loff_t off, blkid_loff_t len) { - ssize_t ret_read = 0; + struct list_head *p; + struct blkid_bufinfo *bf = NULL; + + list_for_each(p, &pr->buffers) { + struct blkid_bufinfo *x = + list_entry(p, struct blkid_bufinfo, bufs); + + if (x->off <= off && off + len <= x->off + x->len) { + DBG(DEBUG_LOWPROBE, + printf("\treuse buffer: off=%jd len=%jd\n", + x->off, x->len)); + bf = x; + break; + } + } + if (!bf) { + ssize_t ret; + + if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) + return NULL; + + /* allocate info and space for data by why call */ + bf = calloc(1, sizeof(struct blkid_bufinfo) + len); + if (!bf) + return NULL; + + bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo); + bf->len = len; + bf->off = off; + INIT_LIST_HEAD(&bf->bufs); - if (off < 0 || len < 0) { DBG(DEBUG_LOWPROBE, - printf("unexpected offset or length of buffer requested\n")); - return NULL; - } - if (off + len <= BLKID_SB_BUFSIZ) { - if (!pr->sbbuf) { - pr->sbbuf = malloc(BLKID_SB_BUFSIZ); - if (!pr->sbbuf) - return NULL; - } - if (!pr->sbbuf_len) { - if (lseek(pr->fd, pr->off, SEEK_SET) < 0) - return NULL; - ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ); - if (ret_read < 0) - ret_read = 0; - pr->sbbuf_len = ret_read; - } - if (off + len > pr->sbbuf_len) + printf("\tbuffer read: off=%jd len=%jd\n", off, len)); + + ret = read(pr->fd, bf->data, len); + if (ret != (ssize_t) len) { + free(bf); return NULL; - return pr->sbbuf + off; - } else { - unsigned char *newbuf = NULL; - - if (len > pr->buf_max) { - newbuf = realloc(pr->buf, len); - if (!newbuf) - return NULL; - pr->buf = newbuf; - pr->buf_max = len; - pr->buf_off = 0; - pr->buf_len = 0; } - if (newbuf || off < pr->buf_off || - off + len > pr->buf_off + pr->buf_len) { + list_add_tail(&bf->bufs, &pr->buffers); + } - if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) - return NULL; + return off ? bf->data + (off - bf->off) : bf->data; +} - ret_read = read(pr->fd, pr->buf, len); - if (ret_read != (ssize_t) len) - return NULL; - pr->buf_off = off; - pr->buf_len = len; - } - return off ? pr->buf + (off - pr->buf_off) : pr->buf; + +static void blkid_probe_reset_buffer(blkid_probe pr) +{ + ssize_t read_ct = 0, len_ct = 0; + + if (!pr || list_empty(&pr->buffers)) + return; + + DBG(DEBUG_LOWPROBE, printf("reseting probing buffers\n")); + + while (!list_empty(&pr->buffers)) { + struct blkid_bufinfo *bf = list_entry(pr->buffers.next, + struct blkid_bufinfo, bufs); + + read_ct++; + len_ct += bf->len; + list_del(&bf->bufs); + free(bf); } + + DBG(DEBUG_LOWPROBE, + printf("buffers summary: %jd bytes by %jd read() call(s)\n", + len_ct, read_ct)); + + INIT_LIST_HEAD(&pr->buffers); +} + +/* + * Small devices need a special care. + */ +int blkid_probe_is_tiny(blkid_probe pr) +{ + return pr && (pr->flags & BLKID_TINY_DEV); } /** @@ -570,6 +573,10 @@ int blkid_probe_set_device(blkid_probe pr, int fd, pr->mode = 0; pr->blkssz = 0; +#if defined(POSIX_FADV_RANDOM) && defined(HAVE_POSIX_FADVISE) + /* Disable read-ahead */ + posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); +#endif if (size) pr->size = size; else { @@ -589,13 +596,23 @@ int blkid_probe_set_device(blkid_probe pr, int fd, if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) pr->devno = sb.st_rdev; + + if (pr->off > pr->size) + goto err; + + /* The probing area cannot be larger than whole device, pr->off + * is offset within the device */ + pr->size -= pr->off; } if (!pr->size) goto err; - DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n", pr->off, pr->size)); + + if (pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode)) + pr->flags |= BLKID_TINY_DEV; + return 0; err: DBG(DEBUG_LOWPROBE, diff --git a/shlibs/blkid/src/save.c b/shlibs/blkid/src/save.c index c61373d5..a1583ecc 100644 --- a/shlibs/blkid/src/save.c +++ b/shlibs/blkid/src/save.c @@ -119,7 +119,7 @@ int blkid_flush_cache(blkid_cache cache) list_for_each(p, &cache->bic_devs) { blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); - if (!dev->bid_type) + if (!dev->bid_type || (dev->bid_flags & BLKID_BID_FL_REMOVABLE)) continue; if ((ret = save_dev(dev, file)) < 0) break; diff --git a/shlibs/blkid/src/superblocks/Makefile.am b/shlibs/blkid/src/superblocks/Makefile.am index 33e5d0c3..f5b88b8e 100644 --- a/shlibs/blkid/src/superblocks/Makefile.am +++ b/shlibs/blkid/src/superblocks/Makefile.am @@ -45,4 +45,5 @@ libblkid_superblocks_la_SOURCES = \ ubifs.c \ bfs.c \ drbd.c \ - vmfs.c + vmfs.c \ + befs.c diff --git a/shlibs/blkid/src/superblocks/befs.c b/shlibs/blkid/src/superblocks/befs.c new file mode 100644 index 00000000..b341402a --- /dev/null +++ b/shlibs/blkid/src/superblocks/befs.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2010 Jeroen Oortwijn <oortwijn@gmail.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 <inttypes.h> + +#include "superblocks.h" + +#define B_OS_NAME_LENGTH 0x20 +#define SUPER_BLOCK_MAGIC1 0x42465331 /* BFS1 */ +#define SUPER_BLOCK_MAGIC2 0xdd121031 +#define SUPER_BLOCK_MAGIC3 0x15b6830e +#define SUPER_BLOCK_FS_ENDIAN 0x42494745 /* BIGE */ +#define INODE_MAGIC1 0x3bbe0ad9 +#define B_UINT64_TYPE 0x554C4C47 /* ULLG */ + +#define FS16_TO_CPU(value, fs_is_le) (fs_is_le ? le16_to_cpu(value) \ + : be16_to_cpu(value)) +#define FS32_TO_CPU(value, fs_is_le) (fs_is_le ? le32_to_cpu(value) \ + : be32_to_cpu(value)) +#define FS64_TO_CPU(value, fs_is_le) (fs_is_le ? le64_to_cpu(value) \ + : be64_to_cpu(value)) + +typedef struct block_run { + int32_t allocation_group; + uint16_t start; + uint16_t len; +} __attribute__((packed)) block_run, inode_addr; + +struct befs_super_block { + char name[B_OS_NAME_LENGTH]; + int32_t magic1; + int32_t fs_byte_order; + uint32_t block_size; + uint32_t block_shift; + int64_t num_blocks; + int64_t used_blocks; + int32_t inode_size; + int32_t magic2; + int32_t blocks_per_ag; + int32_t ag_shift; + int32_t num_ags; + int32_t flags; + block_run log_blocks; + int64_t log_start; + int64_t log_end; + int32_t magic3; + inode_addr root_dir; + inode_addr indices; + int32_t pad[8]; +} __attribute__((packed)); + +typedef struct data_stream { + block_run direct[12]; + int64_t max_direct_range; + block_run indirect; + int64_t max_indirect_range; + block_run double_indirect; + int64_t max_double_indirect_range; + int64_t size; +} __attribute__((packed)) data_stream; + +struct befs_inode { + int32_t magic1; + inode_addr inode_num; + int32_t uid; + int32_t gid; + int32_t mode; + int32_t flags; + int64_t create_time; + int64_t last_modified_time; + inode_addr parent; + inode_addr attributes; + uint32_t type; + int32_t inode_size; + uint32_t etc; + data_stream data; + int32_t pad[4]; + int32_t small_data[1]; +} __attribute__((packed)); + +struct small_data { + uint32_t type; + uint16_t name_size; + uint16_t data_size; + char name[0]; +} __attribute__((packed)); + +static int probe_befs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct befs_super_block *bs; + struct befs_inode *bi; + struct small_data *sd; + int fs_le; + uint64_t volume_id = 0; + const char *version = NULL; + + bs = (struct befs_super_block *) blkid_probe_get_buffer(pr, + mag->sboff - B_OS_NAME_LENGTH, + sizeof(struct befs_super_block)); + if (!bs) + return -1; + + if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 + && le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 + && le32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 + && le32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { + fs_le = 1; + version = "little-endian"; + } else if (be32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 + && be32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 + && be32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 + && be32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { + fs_le = 0; + version = "big-endian"; + } else + return -1; + + bi = (struct befs_inode *) blkid_probe_get_buffer(pr, + (FS32_TO_CPU(bs->root_dir.allocation_group, fs_le) + << FS32_TO_CPU(bs->ag_shift, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)) + + (FS16_TO_CPU(bs->root_dir.start, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)), + FS16_TO_CPU(bs->root_dir.len, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)); + if (!bi) + return -1; + + if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) + return -1; + + /* + * all checks pass, set LABEL and VERSION + */ + if (strlen(bs->name)) + blkid_probe_set_label(pr, (unsigned char *) bs->name, + sizeof(bs->name)); + if (version) + blkid_probe_set_version(pr, version); + + /* + * search for UUID + */ + sd = (struct small_data *) bi->small_data; + + do { + if (FS32_TO_CPU(sd->type, fs_le) == B_UINT64_TYPE + && FS16_TO_CPU(sd->name_size, fs_le) == 12 + && FS16_TO_CPU(sd->data_size, fs_le) == 8 + && strcmp(sd->name, "be:volume_id") == 0) { + volume_id = *(uint64_t *) ((uint8_t *) sd->name + + FS16_TO_CPU(sd->name_size, fs_le) + + 3); + blkid_probe_sprintf_uuid(pr, + (unsigned char *) &volume_id, + sizeof(volume_id), + "%016" PRIx64, + FS64_TO_CPU(volume_id, fs_le)); + break; + } else if (FS32_TO_CPU(sd->type, fs_le) == 0 + && FS16_TO_CPU(sd->name_size, fs_le) == 0 + && FS16_TO_CPU(sd->data_size, fs_le) == 0) { + break; + } + + sd = (struct small_data *) ((uint8_t *) sd + + sizeof(struct small_data) + + FS16_TO_CPU(sd->name_size, fs_le) + 3 + + FS16_TO_CPU(sd->data_size, fs_le) + 1); + + } while ((intptr_t) sd < (intptr_t) bi + + FS32_TO_CPU(bi->inode_size, fs_le) + - sizeof(struct small_data)); + + if (volume_id == 0) { + /* + * TODO: Search for the be:volume_id attribute in the + * attributes directory of the root directory. + */ + } + + return 0; +} + +const struct blkid_idinfo befs_idinfo = +{ + .name = "befs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_befs, + .minsz = 1024 * 1440, + .magics = { + { .magic = "BFS1", .len = 4, .sboff = B_OS_NAME_LENGTH }, + { .magic = "1SFB", .len = 4, .sboff = B_OS_NAME_LENGTH }, + { .magic = "BFS1", .len = 4, .sboff = 0x200 + + B_OS_NAME_LENGTH }, + { .magic = "1SFB", .len = 4, .sboff = 0x200 + + B_OS_NAME_LENGTH }, + { NULL } + } +}; diff --git a/shlibs/blkid/src/superblocks/drbd.c b/shlibs/blkid/src/superblocks/drbd.c index e0bbb4d6..a56486e9 100644 --- a/shlibs/blkid/src/superblocks/drbd.c +++ b/shlibs/blkid/src/superblocks/drbd.c @@ -78,7 +78,8 @@ static int probe_drbd(blkid_probe pr, const struct blkid_idmag *mag) blkid_probe_get_buffer(pr, off, sizeof(struct md_on_disk_08)); - + if (!md) + return -1; if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08) return -1; diff --git a/shlibs/blkid/src/superblocks/gfs.c b/shlibs/blkid/src/superblocks/gfs.c index 8ad81bcb..b2c01630 100644 --- a/shlibs/blkid/src/superblocks/gfs.c +++ b/shlibs/blkid/src/superblocks/gfs.c @@ -108,6 +108,7 @@ 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 }, @@ -120,6 +121,7 @@ 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 }, diff --git a/shlibs/blkid/src/superblocks/jfs.c b/shlibs/blkid/src/superblocks/jfs.c index e6e44505..9a49c674 100644 --- a/shlibs/blkid/src/superblocks/jfs.c +++ b/shlibs/blkid/src/superblocks/jfs.c @@ -61,6 +61,7 @@ const struct blkid_idinfo jfs_idinfo = .name = "jfs", .usage = BLKID_USAGE_FILESYSTEM, .probefunc = probe_jfs, + .minsz = 16 * 1024 * 1024, .magics = { { .magic = "JFS1", .len = 4, .kboff = 32 }, diff --git a/shlibs/blkid/src/superblocks/minix.c b/shlibs/blkid/src/superblocks/minix.c index 784f0758..7b314abc 100644 --- a/shlibs/blkid/src/superblocks/minix.c +++ b/shlibs/blkid/src/superblocks/minix.c @@ -11,20 +11,84 @@ #include "superblocks.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; +}; + +struct minix3_super_block { + uint32_t s_ninodes; + uint16_t s_pad0; + uint16_t s_imap_blocks; + uint16_t s_zmap_blocks; + uint16_t s_firstdatazone; + uint16_t s_log_zone_size; + uint16_t s_pad1; + uint32_t s_max_size; + uint32_t s_zones; + uint16_t s_magic; + uint16_t s_pad2; + uint16_t s_blocksize; + uint8_t s_disk_version; +}; + +#define MINIX_BLOCK_SIZE_BITS 10 +#define MINIX_BLOCK_SIZE (1 << MINIX_BLOCK_SIZE_BITS) + static int probe_minix(blkid_probe pr, const struct blkid_idmag *mag) { + int version; + /* for more details see magic strings below */ switch(mag->magic[1]) { case '\023': - blkid_probe_set_version(pr, "1"); + version = 1; break; case '\044': - blkid_probe_set_version(pr, "2"); + version = 2; break; case '\115': - blkid_probe_set_version(pr, "3"); + version = 3; break; + default: + return -1; + break; + } + + if (version <= 2) { + struct minix_super_block *sb; + uint32_t zones; + + sb = blkid_probe_get_sb(pr, mag, struct minix_super_block); + if (!sb || sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0) + return -1; + + zones = version == 2 ? sb->s_zones : sb->s_nzones; + + /* sanity checks to be sure that the FS is really minix */ + if (sb->s_imap_blocks * MINIX_BLOCK_SIZE * 8 < sb->s_ninodes + 1) + return -1; + if (sb->s_zmap_blocks * MINIX_BLOCK_SIZE * 8 < zones - sb->s_firstdatazone + 1) + return -1; + + } else if (version == 3) { + struct minix3_super_block *sb; + + sb = blkid_probe_get_sb(pr, mag, struct minix3_super_block); + if (!sb || sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0) + return -1; + } + + blkid_probe_sprintf_version(pr, "%d", version); return 0; } diff --git a/shlibs/blkid/src/superblocks/ocfs.c b/shlibs/blkid/src/superblocks/ocfs.c index 6e58b37a..9dbf41b1 100644 --- a/shlibs/blkid/src/superblocks/ocfs.c +++ b/shlibs/blkid/src/superblocks/ocfs.c @@ -174,6 +174,7 @@ const struct blkid_idinfo ocfs_idinfo = .name = "ocfs", .usage = BLKID_USAGE_FILESYSTEM, .probefunc = probe_ocfs, + .minsz = 108 * 1024 * 1024, .magics = { { .magic = "OracleCFS", .len = 9, .kboff = 8 }, @@ -186,6 +187,7 @@ const struct blkid_idinfo ocfs2_idinfo = .name = "ocfs2", .usage = BLKID_USAGE_FILESYSTEM, .probefunc = probe_ocfs2, + .minsz = 108 * 1024 * 1024, .magics = { { .magic = "OCFSV2", .len = 6, .kboff = 1 }, @@ -196,6 +198,7 @@ const struct blkid_idinfo ocfs2_idinfo = } }; +/* Oracle ASM (Automatic Storage Management) */ const struct blkid_idinfo oracleasm_idinfo = { .name = "oracleasm", diff --git a/shlibs/blkid/src/superblocks/reiserfs.c b/shlibs/blkid/src/superblocks/reiserfs.c index 4222a307..921f5237 100644 --- a/shlibs/blkid/src/superblocks/reiserfs.c +++ b/shlibs/blkid/src/superblocks/reiserfs.c @@ -98,6 +98,7 @@ const struct blkid_idinfo reiser_idinfo = .name = "reiserfs", .usage = BLKID_USAGE_FILESYSTEM, .probefunc = probe_reiser, + .minsz = 4096 * 512, /* not sure, this is minimal size of journal */ .magics = { { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 0x34 }, @@ -114,6 +115,7 @@ const struct blkid_idinfo reiser4_idinfo = .name = "reiser4", .usage = BLKID_USAGE_FILESYSTEM, .probefunc = probe_reiser4, + .minsz = 4096 * 512, /* not sure, this is minimal size of journal */ .magics = { { .magic = "ReIsEr4", .len = 7, .kboff = 64 }, diff --git a/shlibs/blkid/src/superblocks/superblocks.c b/shlibs/blkid/src/superblocks/superblocks.c index e77c511d..fd12e5ec 100644 --- a/shlibs/blkid/src/superblocks/superblocks.c +++ b/shlibs/blkid/src/superblocks/superblocks.c @@ -138,7 +138,8 @@ static const struct blkid_idinfo *idinfos[] = &btrfs_idinfo, &ubifs_idinfo, &bfs_idinfo, - &vmfs_fs_idinfo + &vmfs_fs_idinfo, + &befs_idinfo }; /* @@ -310,6 +311,12 @@ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) printf("--> starting probing loop [SUBLKS idx=%d]\n", chn->idx)); + if (pr->size <= 1024 && !S_ISCHR(pr->mode)) + /* Ignore very very small block devices or regular files (e.g. + * extended partitions). Note that size of the UBI char devices + * is 1 byte */ + return 1; + i = chn->idx + 1; for ( ; i < ARRAY_SIZE(idinfos); i++) { @@ -325,8 +332,19 @@ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) continue; id = idinfos[i]; + + if (id->minsz && id->minsz > pr->size) + continue; /* the device is too small */ + mag = id->magics ? &id->magics[0] : NULL; + /* don't probe for RAIDs, swap or journal on floppies */ + if ((id->usage & (BLKID_USAGE_RAID | BLKID_USAGE_OTHER)) && + blkid_probe_is_tiny(pr)) + continue; + + DBG(DEBUG_LOWPROBE, printf("[%d] %s:\n", i, id->name)); + /* try to detect by magic string */ while(mag && mag->magic) { unsigned char *buf; @@ -337,8 +355,8 @@ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) if (buf && !memcmp(mag->magic, buf + (mag->sboff & 0x3ff), mag->len)) { DBG(DEBUG_LOWPROBE, printf( - "%s: magic sboff=%u, kboff=%ld\n", - id->name, mag->sboff, mag->kboff)); + "\tmagic sboff=%u, kboff=%ld\n", + mag->sboff, mag->kboff)); hasmag = 1; off += mag->sboff & 0x3ff; break; @@ -352,8 +370,7 @@ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) /* final check by probing function */ if (id->probefunc) { - DBG(DEBUG_LOWPROBE, printf( - "%s: call probefunc()\n", id->name)); + DBG(DEBUG_LOWPROBE, printf("\tcall probefunc()\n")); if (id->probefunc(pr, mag) != 0) continue; } @@ -393,6 +410,9 @@ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) * The function does not check for filesystems when a RAID or crypto signature * is detected. The function also does not check for collision between RAIDs * and crypto devices. The first detected RAID or crypto device is returned. + * + * The function does not probe for ambivalent results on very small devices + * (e.g. floppies), on small devices the first detected filesystem is returned. */ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn) { @@ -404,6 +424,11 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn) int rc; while ((rc = superblocks_probe(pr, chn)) == 0) { + + if (blkid_probe_is_tiny(pr) && !count) + /* floppy or so -- returns the first result. */ + return 0; + if (!count) { /* save the first result */ nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals); diff --git a/shlibs/blkid/src/superblocks/superblocks.h b/shlibs/blkid/src/superblocks/superblocks.h index 893ae72a..12f197e5 100644 --- a/shlibs/blkid/src/superblocks/superblocks.h +++ b/shlibs/blkid/src/superblocks/superblocks.h @@ -64,6 +64,7 @@ extern const struct blkid_idinfo bfs_idinfo; extern const struct blkid_idinfo vmfs_volume_idinfo; extern const struct blkid_idinfo vmfs_fs_idinfo; extern const struct blkid_idinfo drbd_idinfo; +extern const struct blkid_idinfo befs_idinfo; /* * superblock functions diff --git a/shlibs/blkid/src/superblocks/swap.c b/shlibs/blkid/src/superblocks/swap.c index 4fb4ab7a..8aaa6f31 100644 --- a/shlibs/blkid/src/superblocks/swap.c +++ b/shlibs/blkid/src/superblocks/swap.c @@ -99,6 +99,7 @@ const struct blkid_idinfo swap_idinfo = .name = "swap", .usage = BLKID_USAGE_OTHER, .probefunc = probe_swap, + .minsz = 10 * 4096, /* 10 pages */ .magics = { { "SWAP-SPACE", 10, 0, 0xff6 }, @@ -121,6 +122,7 @@ const struct blkid_idinfo swsuspend_idinfo = .name = "swsuspend", .usage = BLKID_USAGE_OTHER, .probefunc = probe_swsuspend, + .minsz = 10 * 4096, /* 10 pages */ .magics = { { "S1SUSPEND", 9, 0, 0xff6 }, diff --git a/shlibs/blkid/src/superblocks/vfat.c b/shlibs/blkid/src/superblocks/vfat.c index 7587f8dd..b24f6075 100644 --- a/shlibs/blkid/src/superblocks/vfat.c +++ b/shlibs/blkid/src/superblocks/vfat.c @@ -18,62 +18,8 @@ #include "superblocks.h" -/* Yucky misaligned values */ -struct vfat_super_block { -/* 00*/ unsigned char vs_ignored[3]; -/* 03*/ unsigned char vs_sysid[8]; -/* 0b*/ unsigned char vs_sector_size[2]; -/* 0d*/ uint8_t vs_cluster_size; -/* 0e*/ uint16_t vs_reserved; -/* 10*/ uint8_t vs_fats; -/* 11*/ unsigned char vs_dir_entries[2]; -/* 13*/ unsigned char vs_sectors[2]; -/* 15*/ unsigned char vs_media; -/* 16*/ uint16_t vs_fat_length; -/* 18*/ uint16_t vs_secs_track; -/* 1a*/ uint16_t vs_heads; -/* 1c*/ uint32_t vs_hidden; -/* 20*/ uint32_t vs_total_sect; -/* 24*/ uint32_t vs_fat32_length; -/* 28*/ uint16_t vs_flags; -/* 2a*/ uint8_t vs_version[2]; -/* 2c*/ uint32_t vs_root_cluster; -/* 30*/ uint16_t vs_fsinfo_sector; -/* 32*/ uint16_t vs_backup_boot; -/* 34*/ uint16_t vs_reserved2[6]; -/* 40*/ unsigned char vs_unknown[3]; -/* 43*/ unsigned char vs_serno[4]; -/* 47*/ unsigned char vs_label[11]; -/* 52*/ unsigned char vs_magic[8]; -/* 5a*/ unsigned char vs_dummy2[0x1fe - 0x5a]; -/*1fe*/ unsigned char vs_pmagic[2]; -} __attribute__((packed)); - -/* Yucky misaligned values */ -struct msdos_super_block { -/* 00*/ unsigned char ms_ignored[3]; -/* 03*/ unsigned char ms_sysid[8]; -/* 0b*/ unsigned char ms_sector_size[2]; -/* 0d*/ uint8_t ms_cluster_size; -/* 0e*/ uint16_t ms_reserved; -/* 10*/ uint8_t ms_fats; -/* 11*/ unsigned char ms_dir_entries[2]; -/* 13*/ unsigned char ms_sectors[2]; /* =0 iff V3 or later */ -/* 15*/ unsigned char ms_media; -/* 16*/ uint16_t ms_fat_length; /* Sectors per FAT */ -/* 18*/ uint16_t ms_secs_track; -/* 1a*/ uint16_t ms_heads; -/* 1c*/ uint32_t ms_hidden; -/* V3 BPB */ -/* 20*/ uint32_t ms_total_sect; /* iff ms_sectors == 0 */ -/* V4 BPB */ -/* 24*/ unsigned char ms_unknown[3]; /* Phys drive no., resvd, V4 sig (0x29) */ -/* 27*/ unsigned char ms_serno[4]; -/* 2b*/ unsigned char ms_label[11]; -/* 36*/ unsigned char ms_magic[8]; -/* 3e*/ unsigned char ms_dummy2[0x1fe - 0x3e]; -/*1fe*/ unsigned char ms_pmagic[2]; -} __attribute__((packed)); +/* {msdos,vfat}_super_block is defined in ../fat.h */ +#include "fat.h" struct vfat_dir_entry { uint8_t name[11]; @@ -111,25 +57,59 @@ struct fat32_fsinfo { static const char *no_name = "NO NAME "; -static unsigned char *search_fat_label(struct vfat_dir_entry *dir, int count) +/* + * Look for LABEL (name) in the FAT root directory. + */ +static unsigned char *search_fat_label(blkid_probe pr, + uint32_t offset, uint32_t entries) { + struct vfat_dir_entry *ent, *dir = NULL; int i; - for (i = 0; i < count; i++) { - if (dir[i].name[0] == 0x00) + DBG(DEBUG_LOWPROBE, + printf("\tlook for label in root-dir " + "(entries: %d, offset: %d)\n", entries, offset)); + + if (!blkid_probe_is_tiny(pr)) { + /* large disk, read whole root directory */ + dir = (struct vfat_dir_entry *) + blkid_probe_get_buffer(pr, + offset, + entries * sizeof(struct vfat_dir_entry)); + if (!dir) + return NULL; + } + + for (i = 0; i < entries; i++) { + /* + * The root directory could be relatively large (4-16kB). + * Fortunately, the LABEL is usually the first entry in the + * directory. On tiny disks we call read() per entry. + */ + if (!dir) + ent = (struct vfat_dir_entry *) + blkid_probe_get_buffer(pr, + offset + (i * sizeof(struct vfat_dir_entry)), + sizeof(struct vfat_dir_entry)); + else + ent = &dir[i]; + + if (!ent || ent->name[0] == 0x00) break; - if ((dir[i].name[0] == FAT_ENTRY_FREE) || - (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) || - ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)) + if ((ent->name[0] == FAT_ENTRY_FREE) || + (ent->cluster_high != 0 || ent->cluster_low != 0) || + ((ent->attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)) continue; - if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == + if ((ent->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { - return dir[i].name; + DBG(DEBUG_LOWPROBE, + printf("\tfound fs LABEL at entry %d\n", i)); + return ent->name; } } - return 0; + return NULL; } /* @@ -159,7 +139,7 @@ static int probe_fat_nomagic(blkid_probe pr, const struct blkid_idmag *mag) return 1; /* media check */ - if (ms->ms_media < 0xf8 && ms->ms_media != 0xf0) + if (!blkid_fat_valid_media(ms)) return 1; /* fat counts(Linux kernel expects at least 1 FAT table) */ @@ -188,16 +168,14 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) { struct vfat_super_block *vs; struct msdos_super_block *ms; - struct vfat_dir_entry *dir; const unsigned char *vol_label = 0, *tmp; - unsigned char *vol_serno; + unsigned char *vol_serno, vol_label_buf[11]; int maxloop = 100; uint16_t sector_size, dir_entries, reserved; uint32_t sect_count, fat_size, dir_size, cluster_count, fat_length; uint32_t buf_size, start_data_sect, next, root_start, root_dir_entries; const char *version = NULL; - /* non-standard magic strings */ if (mag->len <= 2 && probe_fat_nomagic(pr, mag) != 0) return 1; @@ -211,10 +189,7 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) return -1; /* sector size check */ - tmp = (unsigned char *) &ms->ms_sector_size; - sector_size = tmp[0] + (tmp[1] << 8); - if (sector_size != 0x200 && sector_size != 0x400 && - sector_size != 0x800 && sector_size != 0x1000) + if (!blkid_fat_valid_sectorsize(ms, §or_size)) return 1; tmp = (unsigned char *) &ms->ms_dir_entries; @@ -247,11 +222,11 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) root_dir_entries = vs->vs_dir_entries[0] + (vs->vs_dir_entries[1] << 8); - buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); - dir = (struct vfat_dir_entry *) - blkid_probe_get_buffer(pr, root_start, buf_size); - if (dir) - vol_label = search_fat_label(dir, root_dir_entries); + vol_label = search_fat_label(pr, root_start, root_dir_entries); + if (vol_label) { + memcpy(vol_label_buf, vol_label, 11); + vol_label = vol_label_buf; + } if (!vol_label || !memcmp(vol_label, no_name, 11)) vol_label = ms->ms_label; @@ -284,16 +259,14 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) next_off = (start_data_sect + next_sect_off) * sector_size; - dir = (struct vfat_dir_entry *) - blkid_probe_get_buffer(pr, next_off, buf_size); - if (dir == NULL) - break; - count = buf_size / sizeof(struct vfat_dir_entry); - vol_label = search_fat_label(dir, count); - if (vol_label) + vol_label = search_fat_label(pr, next_off, count); + if (vol_label) { + memcpy(vol_label_buf, vol_label, 11); + vol_label = vol_label_buf; break; + } /* get FAT entry */ fat_entry_off = (reserved * sector_size) + diff --git a/shlibs/blkid/src/superblocks/zfs.c b/shlibs/blkid/src/superblocks/zfs.c index 2d626427..0f580262 100644 --- a/shlibs/blkid/src/superblocks/zfs.c +++ b/shlibs/blkid/src/superblocks/zfs.c @@ -54,6 +54,7 @@ const struct blkid_idinfo zfs_idinfo = .name = "zfs", .usage = BLKID_USAGE_FILESYSTEM, .probefunc = probe_zfs, + .minsz = 64 * 1024 * 1024, .magics = { { .magic = "\0\0\x02\xf5\xb0\x07\xb1\x0c", .len = 8, .kboff = 8 }, |