static inline int is_empty_mbr(unsigned char *mbr) { struct dos_partition *p = mbr_get_partition(mbr, 0); int i, nparts = 0; for (i = 0; i < 4; i++) { if (dos_partition_get_size(p) > 0) nparts++; p++; } return nparts == 0; }
/* * link partition from parent (DOS) to nested BSD partition table */ int fdisk_bsd_link_partition(struct fdisk_context *cxt) { size_t k, i; int rc; struct dos_partition *p; struct bsd_disklabel *d = self_disklabel(cxt); if (!cxt->parent || !fdisk_is_disklabel(cxt->parent, DOS)) { fdisk_warnx(cxt, _("BSD label is not nested within a DOS partition.")); return -EINVAL; } /* ask for DOS partition */ rc = fdisk_ask_partnum(cxt->parent, &k, FALSE); if (rc) return rc; /* ask for BSD partition */ rc = fdisk_ask_partnum(cxt, &i, TRUE); if (rc) return rc; if (i >= BSD_MAXPARTITIONS) return -EINVAL; p = fdisk_dos_get_partition(cxt->parent, k); d->d_partitions[i].p_size = dos_partition_get_size(p); d->d_partitions[i].p_offset = dos_partition_get_start(p); d->d_partitions[i].p_fstype = bsd_translate_fstype(p->sys_ind); if (i >= d->d_npartitions) d->d_npartitions = i + 1; cxt->label->nparts_cur = d->d_npartitions; fdisk_label_set_changed(cxt->label, 1); fdisk_sinfo(cxt, FDISK_INFO_SUCCESS, _("BSD partition '%c' linked to DOS partition %zu."), 'a' + (int) i, k + 1); return 0; }
static int bsd_initlabel (struct fdisk_context *cxt) { struct fdisk_bsd_label *l = self_label(cxt); struct bsd_disklabel *d = self_disklabel(cxt); struct bsd_partition *pp; memset (d, 0, sizeof (struct bsd_disklabel)); d -> d_magic = BSD_DISKMAGIC; if (strncmp (cxt->dev_path, "/dev/sd", 7) == 0) d -> d_type = BSD_DTYPE_SCSI; else d -> d_type = BSD_DTYPE_ST506; #if !defined (__alpha__) d -> d_flags = BSD_D_DOSPART; #else d -> d_flags = 0; #endif d -> d_secsize = DEFAULT_SECTOR_SIZE; /* bytes/sector */ d -> d_nsectors = cxt->geom.sectors; /* sectors/track */ d -> d_ntracks = cxt->geom.heads; /* tracks/cylinder (heads) */ d -> d_ncylinders = cxt->geom.cylinders; d -> d_secpercyl = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */ if (d -> d_secpercyl == 0) d -> d_secpercyl = 1; /* avoid segfaults */ d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; d -> d_rpm = 3600; d -> d_interleave = 1; d -> d_trackskew = 0; d -> d_cylskew = 0; d -> d_headswitch = 0; d -> d_trkseek = 0; d -> d_magic2 = BSD_DISKMAGIC; d -> d_bbsize = BSD_BBSIZE; d -> d_sbsize = BSD_SBSIZE; if (l->dos_part) { d->d_npartitions = 4; pp = &d->d_partitions[2]; /* Partition C should be the NetBSD partition */ pp->p_offset = dos_partition_get_start(l->dos_part); pp->p_size = dos_partition_get_size(l->dos_part); pp->p_fstype = BSD_FS_UNUSED; pp = &d -> d_partitions[3]; /* Partition D should be the whole disk */ pp->p_offset = 0; pp->p_size = d->d_secperunit; pp->p_fstype = BSD_FS_UNUSED; } else { d->d_npartitions = 3; pp = &d->d_partitions[2]; /* Partition C should be the whole disk */ pp->p_offset = 0; pp->p_size = d->d_secperunit; pp->p_fstype = BSD_FS_UNUSED; } return 0; }
static int bsd_add_partition(struct fdisk_context *cxt, struct fdisk_partition *pa) { struct fdisk_bsd_label *l = self_label(cxt); struct bsd_disklabel *d = self_disklabel(cxt); size_t i; unsigned int begin = 0, end; int rc = 0; rc = fdisk_partition_next_partno(pa, cxt, &i); if (rc) return rc; if (i >= BSD_MAXPARTITIONS) return -ERANGE; if (l->dos_part) { begin = dos_partition_get_start(l->dos_part); end = begin + dos_partition_get_size(l->dos_part) - 1; } else end = d->d_secperunit - 1; /* * First sector */ if (pa && pa->start_follow_default) ; else if (pa && pa->start) { if (pa->start < begin || pa->start > end) return -ERANGE; begin = pa->start; } else { struct fdisk_ask *ask = fdisk_new_ask(); if (!ask) return -ENOMEM; fdisk_ask_set_query(ask, fdisk_context_use_cylinders(cxt) ? _("First cylinder") : _("First sector")); fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin)); fdisk_ask_number_set_default(ask, fdisk_cround(cxt, begin)); fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end)); rc = fdisk_do_ask(cxt, ask); begin = fdisk_ask_number_get_result(ask); fdisk_free_ask(ask); if (rc) return rc; if (fdisk_context_use_cylinders(cxt)) begin = (begin - 1) * d->d_secpercyl; } /* * Last sector */ if (pa && pa->end_follow_default) ; else if (pa && pa->size) { if (begin + pa->size > end) return -ERANGE; end = begin + pa->size; } else { /* ask user by dialog */ struct fdisk_ask *ask = fdisk_new_ask(); if (!ask) return -ENOMEM; fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); if (fdisk_context_use_cylinders(cxt)) { fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}")); fdisk_ask_number_set_unit(ask, cxt->sector_size * fdisk_context_get_units_per_sector(cxt)); } else { fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}")); fdisk_ask_number_set_unit(ask,cxt->sector_size); } fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin)); fdisk_ask_number_set_default(ask, fdisk_cround(cxt, end)); fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end)); fdisk_ask_number_set_base(ask, fdisk_cround(cxt, begin)); rc = fdisk_do_ask(cxt, ask); end = fdisk_ask_number_get_result(ask); fdisk_free_ask(ask); if (rc) return rc; if (fdisk_context_use_cylinders(cxt)) end = end * d->d_secpercyl - 1; } d->d_partitions[i].p_size = end - begin + 1; d->d_partitions[i].p_offset = begin; d->d_partitions[i].p_fstype = BSD_FS_UNUSED; if (i >= d->d_npartitions) d->d_npartitions = i + 1; cxt->label->nparts_cur = d->d_npartitions; if (pa && pa->type) bsd_set_parttype(cxt, i, pa->type); fdisk_label_set_changed(cxt->label, 1); return 0; }
static int parse_dos_extended(blkid_probe pr, blkid_parttable tab, uint32_t ex_start, uint32_t ex_size, int ssf) { blkid_partlist ls = blkid_probe_get_partlist(pr); uint32_t cur_start = ex_start, cur_size = ex_size; unsigned char *data; int ct_nodata = 0; /* count ext.partitions without data partitions */ int i; DBG(LOWPROBE, ul_debug("parse EBR [start=%d, size=%d]", ex_start/ssf, ex_size/ssf)); if (ex_start == 0) { DBG(LOWPROBE, ul_debug("Bad offset in primary extended partition -- ignore")); return 0; } while (1) { struct dos_partition *p, *p0; uint32_t start, size; if (++ct_nodata > 100) return BLKID_PROBE_OK; data = blkid_probe_get_sector(pr, cur_start); if (!data) { if (errno) return -errno; goto leave; /* malformed partition? */ } if (!mbr_is_valid_magic(data)) goto leave; p0 = mbr_get_partition(data, 0); /* Usually, the first entry is the real data partition, * the 2nd entry is the next extended partition, or empty, * and the 3rd and 4th entries are unused. * However, DRDOS sometimes has the extended partition as * the first entry (when the data partition is empty), * and OS/2 seems to use all four entries. * -- Linux kernel fs/partitions/dos.c * * See also http://en.wikipedia.org/wiki/Extended_boot_record */ /* Parse data partition */ for (p = p0, i = 0; i < 4; i++, p++) { uint32_t abs_start; blkid_partition par; /* the start is relative to the parental ext.partition */ start = dos_partition_get_start(p) * ssf; size = dos_partition_get_size(p) * ssf; abs_start = cur_start + start; /* absolute start */ if (!size || is_extended(p)) continue; if (i >= 2) { /* extra checks to detect real data on * 3rd and 4th entries */ if (start + size > cur_size) continue; if (abs_start < ex_start) continue; if (abs_start + size > ex_start + ex_size) continue; } /* Avoid recursive non-empty links, see ct_nodata counter */ if (blkid_partlist_get_partition_by_start(ls, abs_start)) { DBG(LOWPROBE, ul_debug("#%d: EBR duplicate data partition [abs start=%u] -- ignore", i + 1, abs_start)); continue; } par = blkid_partlist_add_partition(ls, tab, abs_start, size); if (!par) return -ENOMEM; blkid_partition_set_type(par, p->sys_ind); blkid_partition_set_flags(par, p->boot_ind); blkid_partition_gen_uuid(par); ct_nodata = 0; } /* The first nested ext.partition should be a link to the next * logical partition. Everything other (recursive ext.partitions) * is junk. */ for (p = p0, i = 0; i < 4; i++, p++) { start = dos_partition_get_start(p) * ssf; size = dos_partition_get_size(p) * ssf; if (size && is_extended(p)) { if (start == 0) DBG(LOWPROBE, ul_debug("#%d: EBR link offset is zero -- ignore", i + 1)); else break; } } if (i == 4) goto leave; cur_start = ex_start + start; cur_size = size; } leave: return BLKID_PROBE_OK; }
static int fat_valid_superblock(blkid_probe pr, const struct blkid_idmag *mag, struct msdos_super_block *ms, struct vfat_super_block *vs, uint32_t *cluster_count, uint32_t *fat_size) { uint16_t sector_size, dir_entries, reserved; uint32_t sect_count, __fat_size, dir_size, __cluster_count, fat_length; uint32_t max_count; /* extra check for FATs without magic strings */ if (mag->len <= 2) { /* Old floppies have a valid MBR signature */ if (ms->ms_pmagic[0] != 0x55 || ms->ms_pmagic[1] != 0xAA) return 0; /* * OS/2 and apparently DFSee will place a FAT12/16-like * pseudo-superblock in the first 512 bytes of non-FAT * filesystems --- at least JFS and HPFS, and possibly others. * So we explicitly check for those filesystems at the * FAT12/16 filesystem magic field identifier, and if they are * present, we rule this out as a FAT filesystem, despite the * FAT-like pseudo-header. */ if ((memcmp(ms->ms_magic, "JFS ", 8) == 0) || (memcmp(ms->ms_magic, "HPFS ", 8) == 0)) return 0; } /* fat counts(Linux kernel expects at least 1 FAT table) */ if (!ms->ms_fats) return 0; if (!ms->ms_reserved) return 0; if (!(0xf8 <= ms->ms_media || ms->ms_media == 0xf0)) return 0; if (!is_power_of_2(ms->ms_cluster_size)) return 0; sector_size = unaligned_le16(&ms->ms_sector_size); if (!is_power_of_2(sector_size) || sector_size < 512 || sector_size > 4096) return 0; dir_entries = unaligned_le16(&ms->ms_dir_entries); reserved = le16_to_cpu(ms->ms_reserved); sect_count = unaligned_le16(&ms->ms_sectors); if (sect_count == 0) sect_count = le32_to_cpu(ms->ms_total_sect); fat_length = le16_to_cpu(ms->ms_fat_length); if (fat_length == 0) fat_length = le32_to_cpu(vs->vs_fat32_length); __fat_size = fat_length * ms->ms_fats; dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + (sector_size-1)) / sector_size; __cluster_count = (sect_count - (reserved + __fat_size + dir_size)) / ms->ms_cluster_size; if (!ms->ms_fat_length && vs->vs_fat32_length) max_count = FAT32_MAX; else max_count = __cluster_count > FAT12_MAX ? FAT16_MAX : FAT12_MAX; if (__cluster_count > max_count) return 0; if (fat_size) *fat_size = __fat_size; if (cluster_count) *cluster_count = __cluster_count; #if 0 if (blkid_probe_is_wholedisk(pr)) { /* OK, seems like FAT, but it's possible that we found boot * sector with crazy FAT-like stuff (magic strings, media, * etc..) before MBR. Let's make sure that there is no MBR with * usable partition. */ unsigned char *buf = (unsigned char *) ms; if (mbr_is_valid_magic(buf)) { struct dos_partition *p0 = mbr_get_partition(buf, 0); if (dos_partition_get_size(p0) != 0 && (p0->boot_ind == 0 || p0->boot_ind == 0x80)) return 0; } } #endif return 1; /* valid */ }