xref: /onnv-gate/usr/src/lib/libntfs/common/libntfs/bootsect.c (revision 9663:ace9a2ac3683)
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