diff options
author | Anton Altaparmakov <aia21@cam.ac.uk> | 2007-07-16 14:39:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 15:01:30 -0400 |
commit | 959bc220df38317bed9a677600b3945a8571fc1c (patch) | |
tree | caeeee78786ed9b10994d31545a638dcce441918 | |
parent | 7144521f5ac741e9ad3033953b9d9fdede015ee0 (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>
-rw-r--r-- | fs/partitions/ldm.c | 137 | ||||
-rw-r--r-- | fs/partitions/ldm.h | 2 |
2 files changed, 93 insertions, 46 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 | */ |
680 | static int ldm_relative (const u8 *buffer, int buflen, int base, int offset) | 680 | static 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 | */ |
1057 | static bool ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb) | 1066 | static 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 | } |
diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h index d2e6a3046939..80f63b5fdd9f 100644 --- a/fs/partitions/ldm.h +++ b/fs/partitions/ldm.h | |||
@@ -68,7 +68,7 @@ struct parsed_partitions; | |||
68 | #define VBLK_SIZE_DSK3 12 | 68 | #define VBLK_SIZE_DSK3 12 |
69 | #define VBLK_SIZE_DSK4 45 | 69 | #define VBLK_SIZE_DSK4 45 |
70 | #define VBLK_SIZE_PRT3 28 | 70 | #define VBLK_SIZE_PRT3 28 |
71 | #define VBLK_SIZE_VOL5 59 | 71 | #define VBLK_SIZE_VOL5 58 |
72 | 72 | ||
73 | /* component types */ | 73 | /* component types */ |
74 | #define COMP_STRIPE 0x01 /* Stripe-set */ | 74 | #define COMP_STRIPE 0x01 /* Stripe-set */ |