summaryrefslogtreecommitdiffstats
path: root/shlibs/blkid
diff options
context:
space:
mode:
authorKarel Zak2010-01-19 13:45:51 +0100
committerKarel Zak2010-01-19 14:49:12 +0100
commita47b2ddd0ab6600b53f30b0eaeb67a0d8b3e8668 (patch)
tree9041a3d4ea00d537b9826e75ea842337b46ccd24 /shlibs/blkid
parentlibblkid: read whole SB buffer (69kB) on large disks (diff)
downloadkernel-qcow2-util-linux-a47b2ddd0ab6600b53f30b0eaeb67a0d8b3e8668.tar.gz
kernel-qcow2-util-linux-a47b2ddd0ab6600b53f30b0eaeb67a0d8b3e8668.tar.xz
kernel-qcow2-util-linux-a47b2ddd0ab6600b53f30b0eaeb67a0d8b3e8668.zip
libblkid: don't call read() per FAT dir-entry on large disks
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'shlibs/blkid')
-rw-r--r--shlibs/blkid/src/superblocks/vfat.c45
1 files changed, 36 insertions, 9 deletions
diff --git a/shlibs/blkid/src/superblocks/vfat.c b/shlibs/blkid/src/superblocks/vfat.c
index 1662f1319..29066c34c 100644
--- a/shlibs/blkid/src/superblocks/vfat.c
+++ b/shlibs/blkid/src/superblocks/vfat.c
@@ -111,32 +111,59 @@ struct fat32_fsinfo {
static const char *no_name = "NO NAME ";
+/*
+ * 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 *dir;
+ struct vfat_dir_entry *ent, *dir = NULL;
int i;
- for (i = 0; i < entries; i++) {
+ 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_extra_buffer(pr,
offset + (i * sizeof(struct vfat_dir_entry)),
sizeof(struct vfat_dir_entry));
- if (dir->name[0] == 0x00)
+ else
+ ent = &dir[i];
+
+ if (!ent || ent->name[0] == 0x00)
break;
- if ((dir->name[0] == FAT_ENTRY_FREE) ||
- (dir->cluster_high != 0 || dir->cluster_low != 0) ||
- ((dir->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->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) ==
+ if ((ent->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) ==
FAT_ATTR_VOLUME_ID) {
- return dir->name;
+ DBG(DEBUG_LOWPROBE,
+ printf("\tfound fs LABEL at entry %d\n", i));
+ return ent->name;
}
}
- return 0;
+ return NULL;
}
/*