Lines Matching +full:partitions +full:- +full:table +full:- +full:offset
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * ldm - Support for Windows Logical Disk Manager (Dynamic Disks)
6 * Copyright (c) 2001-2012 Anton Altaparmakov
9 * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
23 * ldm_debug/info/error/crit - Output an error message
57 * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure
59 * @ph: In-memory privhead structure in which to return parsed information
62 * sets up the in-memory privhead structure @ph with the obtained information.
77 ph->ver_major = get_unaligned_be16(data + 0x000C); in ldm_parse_privhead()
78 ph->ver_minor = get_unaligned_be16(data + 0x000E); in ldm_parse_privhead()
79 ph->logical_disk_start = get_unaligned_be64(data + 0x011B); in ldm_parse_privhead()
80 ph->logical_disk_size = get_unaligned_be64(data + 0x0123); in ldm_parse_privhead()
81 ph->config_start = get_unaligned_be64(data + 0x012B); in ldm_parse_privhead()
82 ph->config_size = get_unaligned_be64(data + 0x0133); in ldm_parse_privhead()
84 if (ph->ver_major == 2 && ph->ver_minor == 12) in ldm_parse_privhead()
86 if (!is_vista && (ph->ver_major != 2 || ph->ver_minor != 11)) { in ldm_parse_privhead()
88 " Aborting.", ph->ver_major, ph->ver_minor); in ldm_parse_privhead()
91 ldm_debug("PRIVHEAD version %d.%d (Windows %s).", ph->ver_major, in ldm_parse_privhead()
92 ph->ver_minor, is_vista ? "Vista" : "2000/XP"); in ldm_parse_privhead()
93 if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */ in ldm_parse_privhead()
97 (unsigned long long)ph->config_size); in ldm_parse_privhead()
99 if ((ph->logical_disk_size == 0) || (ph->logical_disk_start + in ldm_parse_privhead()
100 ph->logical_disk_size > ph->config_start)) { in ldm_parse_privhead()
104 if (uuid_parse(data + 0x0030, &ph->disk_id)) { in ldm_parse_privhead()
113 * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure
115 * @toc: In-memory toc structure in which to return parsed information
117 * This parses the LDM Database TOCBLOCK (table of contents) structure supplied
118 * in @data and sets up the in-memory tocblock structure @toc with the obtained
121 * N.B. The *_start and *_size values returned in @toc are not range-checked.
134 strscpy_pad(toc->bitmap1_name, data + 0x24, sizeof(toc->bitmap1_name)); in ldm_parse_tocblock()
135 toc->bitmap1_start = get_unaligned_be64(data + 0x2E); in ldm_parse_tocblock()
136 toc->bitmap1_size = get_unaligned_be64(data + 0x36); in ldm_parse_tocblock()
138 if (strncmp (toc->bitmap1_name, TOC_BITMAP1, in ldm_parse_tocblock()
139 sizeof (toc->bitmap1_name)) != 0) { in ldm_parse_tocblock()
141 TOC_BITMAP1, toc->bitmap1_name); in ldm_parse_tocblock()
144 strscpy_pad(toc->bitmap2_name, data + 0x46, sizeof(toc->bitmap2_name)); in ldm_parse_tocblock()
145 toc->bitmap2_start = get_unaligned_be64(data + 0x50); in ldm_parse_tocblock()
146 toc->bitmap2_size = get_unaligned_be64(data + 0x58); in ldm_parse_tocblock()
147 if (strncmp (toc->bitmap2_name, TOC_BITMAP2, in ldm_parse_tocblock()
148 sizeof (toc->bitmap2_name)) != 0) { in ldm_parse_tocblock()
150 TOC_BITMAP2, toc->bitmap2_name); in ldm_parse_tocblock()
158 * ldm_parse_vmdb - Read the LDM Database VMDB structure
160 * @vm: In-memory vmdb structure in which to return parsed information
163 * the in-memory vmdb structure @vm with the obtained information.
165 * N.B. The *_start, *_size and *_seq values will be range-checked later.
179 vm->ver_major = get_unaligned_be16(data + 0x12); in ldm_parse_vmdb()
180 vm->ver_minor = get_unaligned_be16(data + 0x14); in ldm_parse_vmdb()
181 if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { in ldm_parse_vmdb()
183 "Aborting.", 4, 10, vm->ver_major, vm->ver_minor); in ldm_parse_vmdb()
187 vm->vblk_size = get_unaligned_be32(data + 0x08); in ldm_parse_vmdb()
188 if (vm->vblk_size == 0) { in ldm_parse_vmdb()
193 vm->vblk_offset = get_unaligned_be32(data + 0x0C); in ldm_parse_vmdb()
194 vm->last_vblk_seq = get_unaligned_be32(data + 0x04); in ldm_parse_vmdb()
201 * ldm_compare_privheads - Compare two privhead objects
215 return ((ph1->ver_major == ph2->ver_major) && in ldm_compare_privheads()
216 (ph1->ver_minor == ph2->ver_minor) && in ldm_compare_privheads()
217 (ph1->logical_disk_start == ph2->logical_disk_start) && in ldm_compare_privheads()
218 (ph1->logical_disk_size == ph2->logical_disk_size) && in ldm_compare_privheads()
219 (ph1->config_start == ph2->config_start) && in ldm_compare_privheads()
220 (ph1->config_size == ph2->config_size) && in ldm_compare_privheads()
221 uuid_equal(&ph1->disk_id, &ph2->disk_id)); in ldm_compare_privheads()
225 * ldm_compare_tocblocks - Compare two tocblock objects
239 return ((toc1->bitmap1_start == toc2->bitmap1_start) && in ldm_compare_tocblocks()
240 (toc1->bitmap1_size == toc2->bitmap1_size) && in ldm_compare_tocblocks()
241 (toc1->bitmap2_start == toc2->bitmap2_start) && in ldm_compare_tocblocks()
242 (toc1->bitmap2_size == toc2->bitmap2_size) && in ldm_compare_tocblocks()
243 !strncmp (toc1->bitmap1_name, toc2->bitmap1_name, in ldm_compare_tocblocks()
244 sizeof (toc1->bitmap1_name)) && in ldm_compare_tocblocks()
245 !strncmp (toc1->bitmap2_name, toc2->bitmap2_name, in ldm_compare_tocblocks()
246 sizeof (toc1->bitmap2_name))); in ldm_compare_tocblocks()
250 * ldm_validate_privheads - Compare the primary privhead with its backups
257 * the configuration area (the database). The values are range-checked against
283 /* off[1 & 2] are relative to ph[0]->config_start */ in ldm_validate_privheads()
284 ph[0]->config_start = 0; in ldm_validate_privheads()
288 data = read_part_sector(state, ph[0]->config_start + off[i], in ldm_validate_privheads()
301 break; /* FIXME ignore for now, 3rd PH can fail on odd-sized disks */ in ldm_validate_privheads()
305 num_sects = get_capacity(state->disk); in ldm_validate_privheads()
307 if ((ph[0]->config_start > num_sects) || in ldm_validate_privheads()
308 ((ph[0]->config_start + ph[0]->config_size) > num_sects)) { in ldm_validate_privheads()
313 if ((ph[0]->logical_disk_start > ph[0]->config_start) || in ldm_validate_privheads()
314 ((ph[0]->logical_disk_start + ph[0]->logical_disk_size) in ldm_validate_privheads()
315 > ph[0]->config_start)) { in ldm_validate_privheads()
338 * ldm_validate_tocblocks - Validate the table of contents and its backups
340 * @base: Offset, into @state->disk, of the database
344 * @state->disk and return the parsed information into @toc1.
346 * The offsets and sizes of the configs are range-checked against a privhead.
363 ph = &ldb->ph; in ldm_validate_tocblocks()
364 tb[0] = &ldb->toc; in ldm_validate_tocblocks()
393 if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) || in ldm_validate_tocblocks()
394 ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) > in ldm_validate_tocblocks()
395 ph->config_size)) { in ldm_validate_tocblocks()
414 * ldm_validate_vmdb - Read the VMDB and validate it
416 * @base: Offset, into @bdev, of the database
436 vm = &ldb->vm; in ldm_validate_vmdb()
437 toc = &ldb->toc; in ldm_validate_vmdb()
454 if (vm->vblk_offset != 512) in ldm_validate_vmdb()
455 ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset); in ldm_validate_vmdb()
461 if ((vm->vblk_size * vm->last_vblk_seq) > (toc->bitmap1_size << 9)) { in ldm_validate_vmdb()
475 * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk
479 * disk or not. It looks for an MS-DOS-style partition table containing at
487 * Return: 'true' @state->disk is a dynamic disk
488 * 'false' @state->disk is not a dynamic disk, or an error occurred
511 if (p->sys_ind == LDM_PARTITION) { in ldm_validate_partition_table()
525 * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id
528 * The LDM Database contains a list of all partitions on all dynamic disks.
542 list_for_each (item, &ldb->v_disk) { in ldm_get_disk_objid()
544 if (uuid_equal(&v->vblk.disk.disk_id, &ldb->ph.disk_id)) in ldm_get_disk_objid()
552 * ldm_create_data_partitions - Create data partitions for this device
553 * @pp: List of the partitions parsed so far
556 * The database contains ALL the partitions for ALL disk groups, so we need to
558 * the partitions in the database that belong to this disk.
562 * N.B. This function creates the partitions in the order it finds partition
585 strlcat(pp->pp_buf, " [LDM]", PAGE_SIZE); in ldm_create_data_partitions()
587 /* Create the data partitions */ in ldm_create_data_partitions()
588 list_for_each (item, &ldb->v_part) { in ldm_create_data_partitions()
590 part = &vb->vblk.part; in ldm_create_data_partitions()
592 if (part->disk_id != disk->obj_id) in ldm_create_data_partitions()
595 put_partition (pp, part_num, ldb->ph.logical_disk_start + in ldm_create_data_partitions()
596 part->start, part->size); in ldm_create_data_partitions()
600 strlcat(pp->pp_buf, "\n", PAGE_SIZE); in ldm_create_data_partitions()
606 * ldm_relative - Calculate the next relative offset
610 * @offset: Cumulative size of the previous variable-width fields
612 * Because many of the VBLK fields are variable-width, it's necessary
613 * to calculate each offset based on the previous one and the length
616 * Return: -1 Error, the calculated offset exceeded the size of the buffer
617 * n OK, a range-checked offset into buffer
619 static int ldm_relative(const u8 *buffer, int buflen, int base, int offset) in ldm_relative() argument
622 base += offset; in ldm_relative()
623 if (!buffer || offset < 0 || base > buflen) { in ldm_relative()
626 if (offset < 0) in ldm_relative()
627 ldm_error("offset (%d) < 0", offset); in ldm_relative()
630 return -1; in ldm_relative()
635 return -1; in ldm_relative()
637 return buffer[base] + offset + 1; in ldm_relative()
641 * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order
642 * @block: Pointer to the variable-width number to convert
646 * are stored in big-endian byte order. This function reads one of these
665 while (length--) in ldm_get_vnum()
674 * ldm_get_vstr - Read a length-prefixed string into a buffer
688 * buflen-1, String was truncated.
698 ldm_error ("Truncating string %d -> %d.", length, buflen); in ldm_get_vstr()
699 length = buflen - 1; in ldm_get_vstr()
708 * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure
711 * @vb: In-memory vblk in which to return information
746 comp = &vb->vblk.comp; in ldm_parse_cmp3()
747 ldm_get_vstr (buffer + 0x18 + r_name, comp->state, in ldm_parse_cmp3()
748 sizeof (comp->state)); in ldm_parse_cmp3()
749 comp->type = buffer[0x18 + r_vstate]; in ldm_parse_cmp3()
750 comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate); in ldm_parse_cmp3()
751 comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child); in ldm_parse_cmp3()
752 comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0; in ldm_parse_cmp3()
758 * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure
761 * @vb: In-memory vblk in which to return information
792 dgrp = &vb->vblk.dgrp; in ldm_parse_dgr3()
793 ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id, in ldm_parse_dgr3()
794 sizeof (dgrp->disk_id)); in ldm_parse_dgr3()
799 * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure
802 * @vb: In-memory vblk in which to return information
837 * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure
840 * @vb: In-memory vblk in which to return information
866 disk = &vb->vblk.disk; in ldm_parse_dsk3()
867 ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name, in ldm_parse_dsk3()
868 sizeof (disk->alt_name)); in ldm_parse_dsk3()
869 if (uuid_parse(buffer + 0x19 + r_name, &disk->disk_id)) in ldm_parse_dsk3()
876 * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure
879 * @vb: In-memory vblk in which to return information
903 disk = &vb->vblk.disk; in ldm_parse_dsk4()
904 import_uuid(&disk->disk_id, buffer + 0x18 + r_name); in ldm_parse_dsk4()
909 * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure
912 * @vb: In-memory vblk in which to return information
969 part = &vb->vblk.part; in ldm_parse_prt3()
970 part->start = get_unaligned_be64(buffer + 0x24 + r_name); in ldm_parse_prt3()
971 part->volume_offset = get_unaligned_be64(buffer + 0x2C + r_name); in ldm_parse_prt3()
972 part->size = ldm_get_vnum(buffer + 0x34 + r_name); in ldm_parse_prt3()
973 part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size); in ldm_parse_prt3()
974 part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent); in ldm_parse_prt3()
975 if (vb->flags & VBLK_FLAG_PART_INDEX) in ldm_parse_prt3()
976 part->partnum = buffer[0x35 + r_diskid]; in ldm_parse_prt3()
978 part->partnum = 0; in ldm_parse_prt3()
983 * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure
986 * @vb: In-memory vblk in which to return information
1074 volu = &vb->vblk.volu; in ldm_parse_vol5()
1075 ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type, in ldm_parse_vol5()
1076 sizeof(volu->volume_type)); in ldm_parse_vol5()
1077 memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter, in ldm_parse_vol5()
1078 sizeof(volu->volume_state)); in ldm_parse_vol5()
1079 volu->size = ldm_get_vnum(buffer + 0x3D + r_child); in ldm_parse_vol5()
1080 volu->partition_type = buffer[0x41 + r_size]; in ldm_parse_vol5()
1081 memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid)); in ldm_parse_vol5()
1083 ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint, in ldm_parse_vol5()
1084 sizeof(volu->drive_hint)); in ldm_parse_vol5()
1090 * ldm_parse_vblk - Read a raw VBLK object into a vblk structure
1093 * @vb: In-memory vblk in which to return information
1115 vb->flags = buf[0x12]; in ldm_parse_vblk()
1116 vb->type = buf[0x13]; in ldm_parse_vblk()
1117 vb->obj_id = ldm_get_vnum (buf + 0x18); in ldm_parse_vblk()
1118 ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name)); in ldm_parse_vblk()
1120 switch (vb->type) { in ldm_parse_vblk()
1132 (unsigned long long) vb->obj_id, vb->type); in ldm_parse_vblk()
1135 (unsigned long long) vb->obj_id, vb->type); in ldm_parse_vblk()
1142 * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database
1147 * The VBLKs are sorted into categories. Partitions are also sorted by offset.
1173 switch (vb->type) { in ldm_ldmdb_add()
1176 list_add (&vb->list, &ldb->v_dgrp); in ldm_ldmdb_add()
1180 list_add (&vb->list, &ldb->v_disk); in ldm_ldmdb_add()
1183 list_add (&vb->list, &ldb->v_volu); in ldm_ldmdb_add()
1186 list_add (&vb->list, &ldb->v_comp); in ldm_ldmdb_add()
1190 list_for_each (item, &ldb->v_part) { in ldm_ldmdb_add()
1192 if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) && in ldm_ldmdb_add()
1193 (v->vblk.part.start > vb->vblk.part.start)) { in ldm_ldmdb_add()
1194 list_add_tail (&vb->list, &v->list); in ldm_ldmdb_add()
1198 list_add_tail (&vb->list, &ldb->v_part); in ldm_ldmdb_add()
1205 * ldm_frag_add - Add a VBLK fragment to a list
1243 if (f->group == group) in ldm_frag_add()
1253 f->group = group; in ldm_frag_add()
1254 f->num = num; in ldm_frag_add()
1255 f->rec = rec; in ldm_frag_add()
1256 f->map = 0xFF << num; in ldm_frag_add()
1258 list_add_tail (&f->list, frags); in ldm_frag_add()
1260 if (rec >= f->num) { in ldm_frag_add()
1261 ldm_error("REC value (%d) exceeds NUM value (%d)", rec, f->num); in ldm_frag_add()
1264 if (f->map & (1 << rec)) { in ldm_frag_add()
1266 f->map &= 0x7F; /* Mark the group as broken */ in ldm_frag_add()
1269 f->map |= (1 << rec); in ldm_frag_add()
1271 memcpy(f->data, data, VBLK_SIZE_HEAD); in ldm_frag_add()
1273 size -= VBLK_SIZE_HEAD; in ldm_frag_add()
1274 memcpy(f->data + VBLK_SIZE_HEAD + rec * size, data, size); in ldm_frag_add()
1279 * ldm_frag_free - Free a linked list of VBLK fragments
1297 * ldm_frag_commit - Validate fragmented VBLKs and add them to the database
1317 if (f->map != 0xFF) { in ldm_frag_commit()
1319 f->group, f->map); in ldm_frag_commit()
1323 if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb)) in ldm_frag_commit()
1330 * ldm_get_vblks - Read the on-disk database of VBLKs into memory
1332 * @base: Offset, into @state->disk, of the database
1352 size = ldb->vm.vblk_size; in ldm_get_vblks()
1354 skip = ldb->vm.vblk_offset >> 9; /* Bytes to sectors */ in ldm_get_vblks()
1355 finish = (size * ldb->vm.last_vblk_seq) >> 9; in ldm_get_vblks()
1394 * ldm_free_vblks - Free a linked list of vblk's
1413 * ldm_partition - Find out whether a device is a dynamic disk and handle it
1417 * the partitions necessary in the gendisk structure pointed to by @hd.
1422 * and so on: the actual data containing partitions.
1424 * Return: 1 Success, @state->disk is a dynamic disk and we handled it
1425 * 0 Success, @state->disk is not a dynamic disk
1426 * -1 An error occurred before enough information had been read
1427 * Or @state->disk is a dynamic disk, but it may be corrupted
1433 int result = -1; in ldm_partition()
1448 if (!ldm_validate_privheads(state, &ldb->ph)) in ldm_partition()
1452 base = ldb->ph.config_start; in ldm_partition()
1460 INIT_LIST_HEAD (&ldb->v_dgrp); in ldm_partition()
1461 INIT_LIST_HEAD (&ldb->v_disk); in ldm_partition()
1462 INIT_LIST_HEAD (&ldb->v_volu); in ldm_partition()
1463 INIT_LIST_HEAD (&ldb->v_comp); in ldm_partition()
1464 INIT_LIST_HEAD (&ldb->v_part); in ldm_partition()
1479 ldm_free_vblks (&ldb->v_dgrp); in ldm_partition()
1480 ldm_free_vblks (&ldb->v_disk); in ldm_partition()
1481 ldm_free_vblks (&ldb->v_volu); in ldm_partition()
1482 ldm_free_vblks (&ldb->v_comp); in ldm_partition()
1483 ldm_free_vblks (&ldb->v_part); in ldm_partition()