Index: g_label_ntfs.c =================================================================== --- g_label_ntfs.c (revision 189980) +++ g_label_ntfs.c (working copy) @@ -41,7 +41,7 @@ static void -g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size) +g_label_ntfs_taste(struct g_consumer *cp, char ***labels, size_t *count) { struct g_provider *pp; struct bootfile *bf; @@ -54,7 +54,7 @@ g_topology_assert_not(); - label[0] = '\0'; + *count = 0; pp = cp->provider; filerecp = NULL; @@ -84,26 +84,33 @@ atr = (struct attr *)ap, atr->a_hdr.a_type != -1; ap += atr->a_hdr.reclen) { if (atr->a_hdr.a_type == NTFS_A_VOLUMENAME) { - if(atr->a_r.a_datalen >= size *2){ - label[0] = 0; - goto done; + *count = 1; + *labels = labels_alloc(*count, atr->a_r.a_datalen); + if (*labels == NULL) { + *count = 0; + break; } /* - *UNICODE to ASCII. - * Should we need to use iconv(9)? + * UNICODE to ASCII. + * This will only convert labels consisting of ASCII + * characters, encoded as 16-bit characters whose high + * byte is 0. For proper conversion to UTF-8, iconv + * should be used. */ for (j = 0; j < atr->a_r.a_datalen; j++) { vnchar = *(ap + atr->a_r.a_dataoff + j); if (j & 1) { if (vnchar) { - label[0] = 0; + /* Skip non-ASCII labels */ + labels_free(*labels, *count); + *count = 0; goto done; } } else { - label[j / 2] = vnchar; + (*labels)[0][j / 2] = vnchar; } } - label[j / 2] = 0; + (*labels)[0][j / 2] = '\0'; break; } } Index: g_label_ext2fs.c =================================================================== --- g_label_ext2fs.c (revision 189980) +++ g_label_ext2fs.c (working copy) @@ -49,14 +49,14 @@ } e2sb_t; static void -g_label_ext2fs_taste(struct g_consumer *cp, char *label, size_t size) +g_label_ext2fs_taste(struct g_consumer *cp, char ***labels, size_t *count) { struct g_provider *pp; e2sb_t *fs; g_topology_assert_not(); pp = cp->provider; - label[0] = '\0'; + *count = 0; if ((EXT2FS_SB_OFFSET % pp->sectorsize) != 0) return; @@ -80,8 +80,14 @@ /* Terminate label */ fs->s_volume_name[sizeof(fs->s_volume_name) - 1] = '\0'; - strlcpy(label, fs->s_volume_name, size); + *count = 1; + *labels = labels_alloc(*count, sizeof fs->s_volume_name); + if (*labels != NULL) + strlcpy((*labels)[0], fs->s_volume_name, sizeof fs->s_volume_name); + else + *count = 0; + exit_free: g_free(fs); } Index: g_label_ufs.c =================================================================== --- g_label_ufs.c (revision 189980) +++ g_label_ufs.c (working copy) @@ -44,7 +44,7 @@ static const int superblocks[] = SBLOCKSEARCH; static void -g_label_ufs_taste(struct g_consumer *cp, char *label, size_t size) +g_label_ufs_taste(struct g_consumer *cp, char ***labels, size_t *count) { struct g_provider *pp; int sb, superblock; @@ -52,7 +52,7 @@ g_topology_assert_not(); pp = cp->provider; - label[0] = '\0'; + *count = 0; if (SBLOCKSIZE % cp->provider->sectorsize != 0) return; @@ -65,6 +65,8 @@ * provider based on that. */ for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) { + char **rlabels; + /* * Take care not to issue an invalid I/O request. The offset of * the superblock candidate must be multiples of the provider's @@ -96,12 +98,30 @@ } G_LABEL_DEBUG(1, "%s file system detected on %s.", fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", pp->name); + + /* Create the default label from file system ID */ + *count = 1; + *labels = labels_alloc(*count, 16+3); + if (*labels == NULL) { + *count = 0; + return; + } + sprintf((*labels)[0], "0x%0x%0x", fs->fs_id[0], fs->fs_id[1]); + /* Check for volume label */ if (fs->fs_volname[0] == '\0') { g_free(fs); continue; } - strlcpy(label, fs->fs_volname, size); + (*count)++; + + rlabels = labels_add(labels, *count, sizeof fs->fs_volname); + if (rlabels != NULL) + strlcpy((*labels)[1], fs->fs_volname, + sizeof fs->fs_volname); + else + (*count)--; + g_free(fs); break; } Index: g_label_msdosfs.c =================================================================== --- g_label_msdosfs.c (revision 189980) +++ g_label_msdosfs.c (working copy) @@ -41,8 +41,9 @@ #define LABEL_NO_NAME "NO NAME " static void -g_label_msdosfs_taste(struct g_consumer *cp, char *label, size_t size) +g_label_msdosfs_taste(struct g_consumer *cp, char ***labels, size_t *count) { + char label[FAT_LABEL_SIZE]; struct g_provider *pp; FAT_BSBPB *pfat_bsbpb; FAT32_BSBPB *pfat32_bsbpb; @@ -54,7 +55,8 @@ pp = cp->provider; sector0 = NULL; sector = NULL; - bzero(label, size); + bzero(label, FAT_LABEL_SIZE); + *count = 0; /* Check if the sector size of the medium is a valid FAT sector size. */ switch(pp->sectorsize) { @@ -85,7 +87,6 @@ /* * Test if this is really a FAT volume and determine the FAT type. */ - pfat_bsbpb = (FAT_BSBPB *)sector0; pfat32_bsbpb = (FAT32_BSBPB *)sector0; @@ -111,8 +112,7 @@ pp->name); goto error; } - strlcpy(label, pfat_bsbpb->BS_VolLab, - MIN(size, sizeof(pfat_bsbpb->BS_VolLab) + 1)); + strlcpy(label, pfat_bsbpb->BS_VolLab, FAT_LABEL_SIZE); } else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) { uint32_t fat_FirstDataSector, fat_BytesPerSector, offset; @@ -133,8 +133,7 @@ */ if (strncmp(pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME, sizeof(pfat32_bsbpb->BS_VolLab)) != 0) { - strlcpy(label, pfat32_bsbpb->BS_VolLab, - MIN(size, sizeof(pfat32_bsbpb->BS_VolLab) + 1)); + strlcpy(label, pfat32_bsbpb->BS_VolLab, FAT_LABEL_SIZE); goto endofchecks; } @@ -185,7 +184,7 @@ if (pfat_entry->DIR_Attr & FAT_DES_ATTR_VOLUME_ID) { strlcpy(label, pfat_entry->DIR_Name, - MIN(size, + MIN(FAT_LABEL_SIZE, sizeof(pfat_entry->DIR_Name) + 1)); goto endofchecks; } @@ -200,7 +199,7 @@ } endofchecks: - for (i = size - 1; i > 0; i--) { + for (i = FAT_LABEL_SIZE - 1; i > 0; i--) { if (label[i] == '\0') continue; else if (label[i] == ' ') @@ -208,7 +207,14 @@ else break; } - + if (label[0] != '\0') { + *count = 1; + *labels = labels_alloc(*count, FAT_LABEL_SIZE); + if (*labels != NULL) + strlcpy((*labels)[0], label, FAT_LABEL_SIZE); + else + *count = 0; + } error: if (sector0 != NULL) g_free(sector0); Index: g_label_iso9660.c =================================================================== --- g_label_iso9660.c (revision 189980) +++ g_label_iso9660.c (working copy) @@ -43,15 +43,14 @@ static void -g_label_iso9660_taste(struct g_consumer *cp, char *label, size_t size) +g_label_iso9660_taste(struct g_consumer *cp, char ***labels, size_t *count) { struct g_provider *pp; - char *sector, *volume; - int i; + char *sector, *volume, *tmp; g_topology_assert_not(); pp = cp->provider; - label[0] = '\0'; + *count = 0; if ((ISO9660_OFFSET % pp->sectorsize) != 0) return; @@ -65,17 +64,26 @@ } G_LABEL_DEBUG(1, "ISO9660 file system detected on %s.", pp->name); volume = sector + 0x28; - bzero(label, size); - strlcpy(label, volume, MIN(size, VOLUME_LEN)); - g_free(sector); - for (i = size - 1; i > 0; i--) { - if (label[i] == '\0') + + for (tmp = volume + VOLUME_LEN - 1; tmp > volume; tmp--) { + if (*tmp == '\0') continue; - else if (label[i] == ' ') - label[i] = '\0'; + else if (*tmp == ' ') + *tmp = '\0'; else break; } + + if (volume[0] != '\0') { + *count = 1; + *labels = labels_alloc(*count, VOLUME_LEN); + if (*labels != NULL) + strlcpy((*labels)[0], volume, VOLUME_LEN); + else + *count = 0; + } else + *count = 0; + g_free(sector); } const struct g_label_desc g_label_iso9660 = { Index: g_label.c =================================================================== --- g_label.c (revision 189980) +++ g_label.c (working copy) @@ -268,8 +268,11 @@ G_LABEL_DEBUG(2, "Tasting %s.", pp->name); - if (strcmp(pp->geom->class->name, mp->name) == 0) + if (strcmp(pp->geom->class->name, mp->name) == 0) { + G_LABEL_DEBUG(2, "Skipping %s because it's a label", + pp->name); return (NULL); + } gp = g_new_geomf(mp, "label:taste"); gp->start = g_label_start_taste; @@ -307,15 +310,19 @@ pp->mediasize - pp->sectorsize); } while (0); for (i = 0; g_labels[i] != NULL; i++) { - char label[64]; + char **labels; + size_t n_labels; + int j; g_topology_unlock(); - g_labels[i]->ld_taste(cp, label, sizeof(label)); + g_labels[i]->ld_taste(cp, &labels, &n_labels); g_topology_lock(); - if (label[0] == '\0') + if (n_labels == 0) continue; - g_label_create(NULL, mp, pp, label, g_labels[i]->ld_dir, - pp->mediasize); + for (j = 0; j < n_labels; j++) + g_label_create(NULL, mp, pp, labels[j], + g_labels[i]->ld_dir, pp->mediasize); + labels_free(labels, n_labels); } g_access(cp, -1, 0, 0); end: Index: g_label_reiserfs.c =================================================================== --- g_label_reiserfs.c (revision 189980) +++ g_label_reiserfs.c (working copy) @@ -73,14 +73,14 @@ } static void -g_label_reiserfs_taste(struct g_consumer *cp, char *label, size_t size) +g_label_reiserfs_taste(struct g_consumer *cp, char ***labels, size_t *count) { struct g_provider *pp; reiserfs_sb_t *fs; g_topology_assert_not(); pp = cp->provider; - label[0] = '\0'; + *count = 0; /* Try old format */ fs = g_label_reiserfs_read_super(cp, REISERFS_OLD_DISK_OFFSET); @@ -105,7 +105,13 @@ /* Terminate label */ fs->s_volume_name[sizeof(fs->s_volume_name) - 1] = '\0'; - strlcpy(label, fs->s_volume_name, size); + *count = 1; + *labels = labels_alloc(*count, sizeof fs->s_volume_name); + if (*labels != NULL) + strlcpy((*labels)[0], fs->s_volume_name, + sizeof fs->s_volume_name); + else + *count = 0; exit_free: g_free(fs); Index: g_label_msdosfs.h =================================================================== --- g_label_msdosfs.h (revision 189980) +++ g_label_msdosfs.h (working copy) @@ -138,3 +138,5 @@ uint8_t DIR_FstClusLO[2]; uint8_t DIR_FileSize[4]; } FAT_DES; + +#define FAT_LABEL_SIZE 12 Index: g_label.h =================================================================== --- g_label.h (revision 189980) +++ g_label.h (working copy) @@ -56,8 +56,18 @@ } \ } while (0) -typedef void g_label_taste_t (struct g_consumer *cp, char *label, size_t size); +/* Miscellaneus data */ +static MALLOC_DEFINE(M_GLABEL, "glabel", "GEOM_LABEL Data"); +/* + * G_LABEL protocol for taster functions: *n_labels will be set + * to the number of detected labels. If *n_labels is greater than 0, + * **labels will contain the list of labels, allocated by the + * taster function and freed by g_label. + */ +typedef void g_label_taste_t (struct g_consumer *cp, char ***labels, + size_t *n_labels); + struct g_label_desc { g_label_taste_t *ld_taste; char *ld_dir; @@ -96,4 +106,62 @@ bcopy(data + 20, md->md_label, sizeof(md->md_label)); md->md_provsize = le64dec(data + 36); } + +static __inline char** +labels_alloc(size_t n_labels, size_t size_each) +{ + char **ret; + int i; + + ret = malloc(n_labels * sizeof(char*), M_GLABEL, M_WAITOK); + if (ret == NULL) + return NULL; + for (i = 0; i < n_labels; i++) { + ret[i] = malloc(size_each, M_GLABEL, M_WAITOK); + if (ret[i] == NULL) { + int j; + for (j = 0; j < i; j++) + free(ret[j], M_GLABEL); + return NULL; + } + } + return (ret); +} + +/* + * Adds an element to **labels, reallocating it to fit. In case + * of error nothing is done and NULL is returned. + */ +static __inline char** +labels_add(char ***labels, size_t new_count, size_t size) +{ + char **ret; + + ret = malloc(new_count * sizeof(char*), M_GLABEL, M_WAITOK); + if (ret == NULL) + return NULL; + bcopy(*labels, ret, (new_count - 1)*sizeof(char*)); + + ret[new_count-1] = malloc(size, M_GLABEL, M_WAITOK); + if (ret[new_count-1] == NULL) { + free(ret, M_GLABEL); + return NULL; + } + + free(*labels, M_GLABEL); + *labels = ret; + return (ret); + +} + +static __inline void +labels_free(char **labels, size_t n_labels) +{ + int i; + + for (i = 0; i < n_labels; i++) + free(labels[i], M_GLABEL); + free(labels, M_GLABEL); +} + #endif /* _G_LABEL_H_ */