aboutsummaryrefslogtreecommitdiffstats
path: root/fs/partitions/ldm.c
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cam.ac.uk>2007-07-16 14:39:02 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 15:01:30 -0400
commit959bc220df38317bed9a677600b3945a8571fc1c (patch)
treecaeeee78786ed9b10994d31545a638dcce441918 /fs/partitions/ldm.c
parent7144521f5ac741e9ad3033953b9d9fdede015ee0 (diff)
Fix LDM for new field in the VOL5 VBLK.
Teach LDM about a new field encountered with Windows Vista. This fixes LDM for people using Vista who have disabled drive letter assignment from one or more volumes. Doing this introduces a so far unknown field in the LDM database in the VOL5 VBLK structure which causes the LDM driver to fail to parse the VBLK structure and hence LDM fails to parse the disk altogether. This patch teaches the driver about this field. Thanks got to Ashton Mills <amills@iinet.com.au> for reporting the problem and working with me on getting it fixed. It is now working for him. Signed-off-by: Anton Altaparmakov <aia21@cantab.net> CC: Richard Russon <ldm@flatcap.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/partitions/ldm.c')
-rw-r--r--fs/partitions/ldm.c137
1 files changed, 92 insertions, 45 deletions
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
index 99873a2b4cbc..e7dd1d4e3473 100644
--- a/fs/partitions/ldm.c
+++ b/fs/partitions/ldm.c
@@ -677,15 +677,24 @@ static bool ldm_create_data_partitions (struct parsed_partitions *pp,
677 * Return: -1 Error, the calculated offset exceeded the size of the buffer 677 * Return: -1 Error, the calculated offset exceeded the size of the buffer
678 * n OK, a range-checked offset into buffer 678 * n OK, a range-checked offset into buffer
679 */ 679 */
680static int ldm_relative (const u8 *buffer, int buflen, int base, int offset) 680static int ldm_relative(const u8 *buffer, int buflen, int base, int offset)
681{ 681{
682 682
683 base += offset; 683 base += offset;
684 if ((!buffer) || (offset < 0) || (base > buflen)) 684 if (!buffer || offset < 0 || base > buflen) {
685 if (!buffer)
686 ldm_error("!buffer");
687 if (offset < 0)
688 ldm_error("offset (%d) < 0", offset);
689 if (base > buflen)
690 ldm_error("base (%d) > buflen (%d)", base, buflen);
685 return -1; 691 return -1;
686 if ((base + buffer[base]) >= buflen) 692 }
693 if (base + buffer[base] >= buflen) {
694 ldm_error("base (%d) + buffer[base] (%d) >= buflen (%d)", base,
695 buffer[base], buflen);
687 return -1; 696 return -1;
688 697 }
689 return buffer[base] + offset + 1; 698 return buffer[base] + offset + 1;
690} 699}
691 700
@@ -1054,60 +1063,98 @@ static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb)
1054 * Return: 'true' @vb contains a Volume VBLK 1063 * Return: 'true' @vb contains a Volume VBLK
1055 * 'false' @vb contents are not defined 1064 * 'false' @vb contents are not defined
1056 */ 1065 */
1057static bool ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb) 1066static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb)
1058{ 1067{
1059 int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2; 1068 int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size;
1060 int r_drive, len; 1069 int r_id1, r_id2, r_size2, r_drive, len;
1061 struct vblk_volu *volu; 1070 struct vblk_volu *volu;
1062 1071
1063 BUG_ON (!buffer || !vb); 1072 BUG_ON(!buffer || !vb);
1064 1073 r_objid = ldm_relative(buffer, buflen, 0x18, 0);
1065 r_objid = ldm_relative (buffer, buflen, 0x18, 0); 1074 if (r_objid < 0) {
1066 r_name = ldm_relative (buffer, buflen, 0x18, r_objid); 1075 ldm_error("r_objid %d < 0", r_objid);
1067 r_vtype = ldm_relative (buffer, buflen, 0x18, r_name); 1076 return false;
1068 r_child = ldm_relative (buffer, buflen, 0x2E, r_vtype); 1077 }
1069 r_size = ldm_relative (buffer, buflen, 0x3E, r_child); 1078 r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
1070 1079 if (r_name < 0) {
1071 if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) 1080 ldm_error("r_name %d < 0", r_name);
1072 r_id1 = ldm_relative (buffer, buflen, 0x53, r_size); 1081 return false;
1073 else 1082 }
1083 r_vtype = ldm_relative(buffer, buflen, 0x18, r_name);
1084 if (r_vtype < 0) {
1085 ldm_error("r_vtype %d < 0", r_vtype);
1086 return false;
1087 }
1088 r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype);
1089 if (r_disable_drive_letter < 0) {
1090 ldm_error("r_disable_drive_letter %d < 0",
1091 r_disable_drive_letter);
1092 return false;
1093 }
1094 r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter);
1095 if (r_child < 0) {
1096 ldm_error("r_child %d < 0", r_child);
1097 return false;
1098 }
1099 r_size = ldm_relative(buffer, buflen, 0x3D, r_child);
1100 if (r_size < 0) {
1101 ldm_error("r_size %d < 0", r_size);
1102 return false;
1103 }
1104 if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) {
1105 r_id1 = ldm_relative(buffer, buflen, 0x52, r_size);
1106 if (r_id1 < 0) {
1107 ldm_error("r_id1 %d < 0", r_id1);
1108 return false;
1109 }
1110 } else
1074 r_id1 = r_size; 1111 r_id1 = r_size;
1075 1112 if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) {
1076 if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) 1113 r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1);
1077 r_id2 = ldm_relative (buffer, buflen, 0x53, r_id1); 1114 if (r_id2 < 0) {
1078 else 1115 ldm_error("r_id2 %d < 0", r_id2);
1116 return false;
1117 }
1118 } else
1079 r_id2 = r_id1; 1119 r_id2 = r_id1;
1080 1120 if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) {
1081 if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) 1121 r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2);
1082 r_size2 = ldm_relative (buffer, buflen, 0x53, r_id2); 1122 if (r_size2 < 0) {
1083 else 1123 ldm_error("r_size2 %d < 0", r_size2);
1124 return false;
1125 }
1126 } else
1084 r_size2 = r_id2; 1127 r_size2 = r_id2;
1085 1128 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1086 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) 1129 r_drive = ldm_relative(buffer, buflen, 0x52, r_size2);
1087 r_drive = ldm_relative (buffer, buflen, 0x53, r_size2); 1130 if (r_drive < 0) {
1088 else 1131 ldm_error("r_drive %d < 0", r_drive);
1132 return false;
1133 }
1134 } else
1089 r_drive = r_size2; 1135 r_drive = r_size2;
1090
1091 len = r_drive; 1136 len = r_drive;
1092 if (len < 0) 1137 if (len < 0) {
1138 ldm_error("len %d < 0", len);
1093 return false; 1139 return false;
1094 1140 }
1095 len += VBLK_SIZE_VOL5; 1141 len += VBLK_SIZE_VOL5;
1096 if (len != BE32 (buffer + 0x14)) 1142 if (len > BE32(buffer + 0x14)) {
1143 ldm_error("len %d > BE32(buffer + 0x14) %d", len,
1144 BE32(buffer + 0x14));
1097 return false; 1145 return false;
1098 1146 }
1099 volu = &vb->vblk.volu; 1147 volu = &vb->vblk.volu;
1100 1148 ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type,
1101 ldm_get_vstr (buffer + 0x18 + r_name, volu->volume_type, 1149 sizeof(volu->volume_type));
1102 sizeof (volu->volume_type)); 1150 memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter,
1103 memcpy (volu->volume_state, buffer + 0x19 + r_vtype, 1151 sizeof(volu->volume_state));
1104 sizeof (volu->volume_state)); 1152 volu->size = ldm_get_vnum(buffer + 0x3D + r_child);
1105 volu->size = ldm_get_vnum (buffer + 0x3E + r_child); 1153 volu->partition_type = buffer[0x41 + r_size];
1106 volu->partition_type = buffer[0x42 + r_size]; 1154 memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid));
1107 memcpy (volu->guid, buffer + 0x43 + r_size, sizeof (volu->guid));
1108 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) { 1155 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1109 ldm_get_vstr (buffer + 0x53 + r_size, volu->drive_hint, 1156 ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint,
1110 sizeof (volu->drive_hint)); 1157 sizeof(volu->drive_hint));
1111 } 1158 }
1112 return true; 1159 return true;
1113} 1160}