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