1 /**
2 * bootsect.c - Boot sector handling code. Part of the Linux-NTFS project.
3 *
4 * Copyright (c) 2000-2006 Anton Altaparmakov
5 * Copyright (c) 2005 Yura Pakhuchiy
6 *
7 * This program/include file is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program/include file is distributed in the hope that it will be
13 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program (in the main directory of the Linux-NTFS
19 * distribution in the file COPYING); if not, write to the Free Software
20 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #ifdef HAVE_STDIO_H
28 #include <stdio.h>
29 #endif
30 #ifdef HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36 #ifdef HAVE_ERRNO_H
37 #include <errno.h>
38 #endif
39
40 #include "compat.h"
41 #include "bootsect.h"
42 #include "debug.h"
43 #include "logging.h"
44
45 /**
46 * ntfs_boot_sector_is_ntfs - check if buffer contains a valid ntfs boot sector
47 * @b: buffer containing putative boot sector to analyze
48 * @silent: if zero, output progress messages to stderr
49 *
50 * Check if the buffer @b contains a valid ntfs boot sector. The buffer @b
51 * must be at least 512 bytes in size.
52 *
53 * If @silent is zero, output progress messages to stderr. Otherwise, do not
54 * output any messages (except when configured with --enable-debug in which
55 * case warning/debug messages may be displayed).
56 *
57 * Return TRUE if @b contains a valid ntfs boot sector and FALSE if not.
58 */
ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR * b,const BOOL silent)59 BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b,
60 const BOOL silent __attribute__((unused)))
61 {
62 u32 i;
63
64 ntfs_log_debug("\nBeginning bootsector check...\n");
65
66 /*
67 * Check that checksum == sum of u32 values from b to the checksum
68 * field. If checksum is zero, no checking is done. We will work when
69 * the checksum test fails, since some utilities update the boot sector
70 * ignoring the checksum which leaves the checksum out-of-date. We
71 * report a warning if this is the case.
72 */
73 if ((void*)b < (void*)&b->checksum && b->checksum) {
74 u32 *u = (u32 *)b;
75 u32 *bi = (u32 *)(&b->checksum);
76
77 ntfs_log_debug("Calculating bootsector checksum... ");
78 for (i = 0; u < bi; ++u)
79 i += le32_to_cpup(u);
80 if (le32_to_cpu(b->checksum) && le32_to_cpu(b->checksum) != i) {
81 ntfs_log_debug("FAILED\n");
82 ntfs_log_debug("The NTFS bootsector contains an "
83 "incorrect checksum.");
84 } else
85 ntfs_log_debug("OK\n");
86 }
87
88 /* Check OEMidentifier is "NTFS " */
89 ntfs_log_debug("Checking OEMid... ");
90 if (b->oem_id != NTFS_SB_MAGIC) /* "NTFS " */
91 goto not_ntfs;
92 ntfs_log_debug("OK\n");
93
94 /* Check bytes per sector value is between 256 and 4096. */
95 ntfs_log_debug("Checking bytes per sector... ");
96 if (le16_to_cpu(b->bpb.bytes_per_sector) < 0x100 ||
97 le16_to_cpu(b->bpb.bytes_per_sector) > 0x1000)
98 goto not_ntfs;
99 ntfs_log_debug("OK\n");
100
101 /* Check sectors per cluster value is valid. */
102 ntfs_log_debug("Checking sectors per cluster... ");
103 switch (b->bpb.sectors_per_cluster) {
104 case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
105 break;
106 default:
107 goto not_ntfs;
108 }
109 ntfs_log_debug("OK\n");
110
111 /* Check the cluster size is not above 65536 bytes. */
112 ntfs_log_debug("Checking cluster size... ");
113 if ((u32)le16_to_cpu(b->bpb.bytes_per_sector) *
114 b->bpb.sectors_per_cluster > 0x10000)
115 goto not_ntfs;
116 ntfs_log_debug("OK\n");
117
118 /* Check reserved/unused fields are really zero. */
119 ntfs_log_debug("Checking reserved fields are zero... ");
120 if (le16_to_cpu(b->bpb.reserved_sectors) ||
121 le16_to_cpu(b->bpb.root_entries) ||
122 le16_to_cpu(b->bpb.sectors) ||
123 le16_to_cpu(b->bpb.sectors_per_fat) ||
124 le32_to_cpu(b->bpb.large_sectors) ||
125 b->bpb.fats)
126 goto not_ntfs;
127 ntfs_log_debug("OK\n");
128
129 /* Check clusters per file mft record value is valid. */
130 ntfs_log_debug("Checking clusters per mft record... ");
131 if ((u8)b->clusters_per_mft_record < 0xe1 ||
132 (u8)b->clusters_per_mft_record > 0xf7) {
133 switch (b->clusters_per_mft_record) {
134 case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
135 break;
136 default:
137 goto not_ntfs;
138 }
139 }
140 ntfs_log_debug("OK\n");
141
142 /* Check clusters per index block value is valid. */
143 ntfs_log_debug("Checking clusters per index block... ");
144 if ((u8)b->clusters_per_index_record < 0xe1 ||
145 (u8)b->clusters_per_index_record > 0xf7) {
146 switch (b->clusters_per_index_record) {
147 case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
148 break;
149 default:
150 goto not_ntfs;
151 }
152 }
153 ntfs_log_debug("OK\n");
154
155 if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
156 ntfs_log_debug("Warning: Bootsector has invalid end of sector "
157 "marker.\n");
158
159 ntfs_log_debug("Bootsector check completed successfully.\n");
160 return TRUE;
161 not_ntfs:
162 ntfs_log_debug("FAILED\n");
163 ntfs_log_debug("Bootsector check failed. Aborting...\n");
164 return FALSE;
165 }
166
167 /**
168 * ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
169 * @vol: ntfs_volume to setup
170 * @bs: buffer containing ntfs boot sector to parse
171 *
172 * Parse the ntfs bootsector @bs and setup the ntfs volume @vol with the
173 * obtained values.
174 *
175 * Return 0 on success or -1 on error with errno set to the error code EINVAL.
176 */
ntfs_boot_sector_parse(ntfs_volume * vol,const NTFS_BOOT_SECTOR * bs)177 int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
178 {
179 u8 sectors_per_cluster;
180 s8 c;
181
182 /* We return -1 with errno = EINVAL on error. */
183 errno = EINVAL;
184
185 vol->sector_size = le16_to_cpu(bs->bpb.bytes_per_sector);
186 vol->sector_size_bits = ffs(vol->sector_size) - 1;
187 ntfs_log_debug("SectorSize = 0x%x\n", vol->sector_size);
188 ntfs_log_debug("SectorSizeBits = %u\n", vol->sector_size_bits);
189 /*
190 * The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
191 * below or equal the number_of_clusters) really belong in the
192 * ntfs_boot_sector_is_ntfs but in this way we can just do this once.
193 */
194 sectors_per_cluster = bs->bpb.sectors_per_cluster;
195 ntfs_log_debug("NumberOfSectors = %lli\n",
196 sle64_to_cpu(bs->number_of_sectors));
197 ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
198 if (sectors_per_cluster & (sectors_per_cluster - 1)) {
199 ntfs_log_debug("Error: %s is not a valid NTFS partition! "
200 "sectors_per_cluster is not a power of 2.\n",
201 vol->u.dev->d_name);
202 return -1;
203 }
204 vol->nr_clusters = sle64_to_cpu(bs->number_of_sectors) >>
205 (ffs(sectors_per_cluster) - 1);
206
207 vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
208 vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
209 ntfs_log_debug("MFT LCN = 0x%llx\n", vol->mft_lcn);
210 ntfs_log_debug("MFTMirr LCN = 0x%llx\n", vol->mftmirr_lcn);
211 if (vol->mft_lcn > vol->nr_clusters ||
212 vol->mftmirr_lcn > vol->nr_clusters) {
213 ntfs_log_debug("Error: %s is not a valid NTFS partition!\n",
214 vol->u.dev->d_name);
215 ntfs_log_debug("($Mft LCN or $MftMirr LCN is greater than the "
216 "number of clusters!)\n");
217 return -1;
218 }
219 vol->cluster_size = sectors_per_cluster * vol->sector_size;
220 if (vol->cluster_size & (vol->cluster_size - 1)) {
221 ntfs_log_debug("Error: %s is not a valid NTFS partition! "
222 "cluster_size is not a power of 2.\n",
223 vol->u.dev->d_name);
224 return -1;
225 }
226 vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
227 /*
228 * Need to get the clusters per mft record and handle it if it is
229 * negative. Then calculate the mft_record_size. A value of 0x80 is
230 * illegal, thus signed char is actually ok!
231 */
232 c = bs->clusters_per_mft_record;
233 ntfs_log_debug("ClusterSize = 0x%x\n", (unsigned)vol->cluster_size);
234 ntfs_log_debug("ClusterSizeBits = %u\n", vol->cluster_size_bits);
235 ntfs_log_debug("ClustersPerMftRecord = 0x%x\n", c);
236 /*
237 * When clusters_per_mft_record is negative, it means that it is to
238 * be taken to be the negative base 2 logarithm of the mft_record_size
239 * min bytes. Then:
240 * mft_record_size = 2^(-clusters_per_mft_record) bytes.
241 */
242 if (c < 0)
243 vol->mft_record_size = 1 << -c;
244 else
245 vol->mft_record_size = c << vol->cluster_size_bits;
246 if (vol->mft_record_size & (vol->mft_record_size - 1)) {
247 ntfs_log_debug("Error: %s is not a valid NTFS partition! "
248 "mft_record_size is not a power of 2.\n",
249 vol->u.dev->d_name);
250 return -1;
251 }
252 vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
253 ntfs_log_debug("MftRecordSize = 0x%x\n",
254 (unsigned)vol->mft_record_size);
255 ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
256 /* Same as above for INDX record. */
257 c = bs->clusters_per_index_record;
258 ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
259 if (c < 0)
260 vol->indx_record_size = 1 << -c;
261 else
262 vol->indx_record_size = c << vol->cluster_size_bits;
263 vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
264 ntfs_log_debug("INDXRecordSize = 0x%x\n",
265 (unsigned)vol->indx_record_size);
266 ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
267 /*
268 * Windows cares only about first 4 records in $MFTMirr and inores
269 * everything beyend them.
270 */
271 vol->mftmirr_size = 4;
272 return 0;
273 }
274