blob: 5a92f568410d2ad895f450c83ff0de5e6d2b8fd6 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/* fat.c - Read/write access to the FAT
2
3 Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
4 Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Matt Mower18794c82015-11-11 16:22:45 -06005 Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
bigbiff bigbiff9c754052013-01-09 09:09:08 -05006
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 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. If not, see <http://www.gnu.org/licenses/>.
19
Matt Mower18794c82015-11-11 16:22:45 -060020 The complete text of the GNU General Public License
bigbiff bigbiff9c754052013-01-09 09:09:08 -050021 can be found in /usr/share/common-licenses/GPL-3 file.
22*/
23
24/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
25 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31
32#include "common.h"
Matt Mower18794c82015-11-11 16:22:45 -060033#include "fsck.fat.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050034#include "io.h"
35#include "check.h"
36#include "fat.h"
37
38/**
39 * Fetch the FAT entry for a specified cluster.
40 *
41 * @param[out] entry Cluster to which cluster of interest is linked
42 * @param[in] fat FAT table for the partition
43 * @param[in] cluster Cluster of interest
44 * @param[in] fs Information from the FAT boot sectors (bits per FAT entry)
45 */
Matt Mower18794c82015-11-11 16:22:45 -060046void get_fat(FAT_ENTRY * entry, void *fat, uint32_t cluster, DOS_FS * fs)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050047{
48 unsigned char *ptr;
49
50 switch (fs->fat_bits) {
51 case 12:
52 ptr = &((unsigned char *)fat)[cluster * 3 / 2];
53 entry->value = 0xfff & (cluster & 1 ? (ptr[0] >> 4) | (ptr[1] << 4) :
54 (ptr[0] | ptr[1] << 8));
55 break;
56 case 16:
Matt Mower18794c82015-11-11 16:22:45 -060057 entry->value = le16toh(((unsigned short *)fat)[cluster]);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050058 break;
59 case 32:
60 /* According to M$, the high 4 bits of a FAT32 entry are reserved and
61 * are not part of the cluster number. So we cut them off. */
62 {
Matt Mower18794c82015-11-11 16:22:45 -060063 uint32_t e = le32toh(((unsigned int *)fat)[cluster]);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050064 entry->value = e & 0xfffffff;
65 entry->reserved = e >> 28;
66 }
67 break;
68 default:
69 die("Bad FAT entry size: %d bits.", fs->fat_bits);
70 }
71}
72
73/**
74 * Build a bookkeeping structure from the partition's FAT table.
75 * If the partition has multiple FATs and they don't agree, try to pick a winner,
76 * and queue a command to overwrite the loser.
77 * One error that is fixed here is a cluster that links to something out of range.
78 *
79 * @param[inout] fs Information about the filesystem
80 */
81void read_fat(DOS_FS * fs)
82{
Matt Mower18794c82015-11-11 16:22:45 -060083 int eff_size, alloc_size;
84 uint32_t i;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050085 void *first, *second = NULL;
86 int first_ok, second_ok;
Matt Mower18794c82015-11-11 16:22:45 -060087 uint32_t total_num_clusters;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050088
89 /* Clean up from previous pass */
Matt Mower18794c82015-11-11 16:22:45 -060090 if (fs->fat)
91 free(fs->fat);
92 if (fs->cluster_owner)
93 free(fs->cluster_owner);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050094 fs->fat = NULL;
95 fs->cluster_owner = NULL;
96
97 total_num_clusters = fs->clusters + 2UL;
98 eff_size = (total_num_clusters * fs->fat_bits + 7) / 8ULL;
Matt Mower18794c82015-11-11 16:22:45 -060099
100 if (fs->fat_bits != 12)
101 alloc_size = eff_size;
102 else
103 /* round up to an even number of FAT entries to avoid special
104 * casing the last entry in get_fat() */
105 alloc_size = (total_num_clusters * 12 + 23) / 24 * 3;
106
107 first = alloc(alloc_size);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500108 fs_read(fs->fat_start, eff_size, first);
109 if (fs->nfats > 1) {
Matt Mower18794c82015-11-11 16:22:45 -0600110 second = alloc(alloc_size);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500111 fs_read(fs->fat_start + fs->fat_size, eff_size, second);
112 }
113 if (second && memcmp(first, second, eff_size) != 0) {
114 FAT_ENTRY first_media, second_media;
115 get_fat(&first_media, first, 0, fs);
116 get_fat(&second_media, second, 0, fs);
117 first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
118 second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
119 if (first_ok && !second_ok) {
120 printf("FATs differ - using first FAT.\n");
121 fs_write(fs->fat_start + fs->fat_size, eff_size, first);
122 }
123 if (!first_ok && second_ok) {
124 printf("FATs differ - using second FAT.\n");
125 fs_write(fs->fat_start, eff_size, second);
126 memcpy(first, second, eff_size);
127 }
128 if (first_ok && second_ok) {
129 if (interactive) {
130 printf("FATs differ but appear to be intact. Use which FAT ?\n"
131 "1) Use first FAT\n2) Use second FAT\n");
132 if (get_key("12", "?") == '1') {
133 fs_write(fs->fat_start + fs->fat_size, eff_size, first);
134 } else {
135 fs_write(fs->fat_start, eff_size, second);
136 memcpy(first, second, eff_size);
137 }
138 } else {
139 printf("FATs differ but appear to be intact. Using first "
140 "FAT.\n");
141 fs_write(fs->fat_start + fs->fat_size, eff_size, first);
142 }
143 }
144 if (!first_ok && !second_ok) {
145 printf("Both FATs appear to be corrupt. Giving up.\n");
146 exit(1);
147 }
148 }
149 if (second) {
150 free(second);
151 }
152 fs->fat = (unsigned char *)first;
153
154 fs->cluster_owner = alloc(total_num_clusters * sizeof(DOS_FILE *));
155 memset(fs->cluster_owner, 0, (total_num_clusters * sizeof(DOS_FILE *)));
156
157 /* Truncate any cluster chains that link to something out of range */
158 for (i = 2; i < fs->clusters + 2; i++) {
159 FAT_ENTRY curEntry;
160 get_fat(&curEntry, fs->fat, i, fs);
161 if (curEntry.value == 1) {
Matt Mower18794c82015-11-11 16:22:45 -0600162 printf("Cluster %ld out of range (1). Setting to EOF.\n", (long)(i - 2));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500163 set_fat(fs, i, -1);
164 }
165 if (curEntry.value >= fs->clusters + 2 &&
166 (curEntry.value < FAT_MIN_BAD(fs))) {
167 printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
Matt Mower18794c82015-11-11 16:22:45 -0600168 (long)(i - 2), (long)curEntry.value, (long)(fs->clusters + 2 - 1));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500169 set_fat(fs, i, -1);
170 }
171 }
172}
173
174/**
175 * Update the FAT entry for a specified cluster
176 * (i.e., change the cluster it links to).
177 * Queue a command to write out this change.
178 *
179 * @param[in,out] fs Information about the filesystem
180 * @param[in] cluster Cluster to change
181 * @param[in] new Cluster to link to
182 * Special values:
183 * 0 == free cluster
184 * -1 == end-of-chain
185 * -2 == bad cluster
186 */
Matt Mower18794c82015-11-11 16:22:45 -0600187void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500188{
189 unsigned char *data = NULL;
190 int size;
191 loff_t offs;
192
Matt Mower18794c82015-11-11 16:22:45 -0600193 if (new == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500194 new = FAT_EOF(fs);
195 else if ((long)new == -2)
196 new = FAT_BAD(fs);
197 switch (fs->fat_bits) {
198 case 12:
199 data = fs->fat + cluster * 3 / 2;
200 offs = fs->fat_start + cluster * 3 / 2;
201 if (cluster & 1) {
202 FAT_ENTRY prevEntry;
203 get_fat(&prevEntry, fs->fat, cluster - 1, fs);
204 data[0] = ((new & 0xf) << 4) | (prevEntry.value >> 8);
205 data[1] = new >> 4;
206 } else {
207 FAT_ENTRY subseqEntry;
208 get_fat(&subseqEntry, fs->fat, cluster + 1, fs);
209 data[0] = new & 0xff;
210 data[1] = (new >> 8) | (cluster == fs->clusters - 1 ? 0 :
211 (0xff & subseqEntry.value) << 4);
212 }
213 size = 2;
214 break;
215 case 16:
216 data = fs->fat + cluster * 2;
217 offs = fs->fat_start + cluster * 2;
Matt Mower18794c82015-11-11 16:22:45 -0600218 *(unsigned short *)data = htole16(new);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500219 size = 2;
220 break;
221 case 32:
222 {
223 FAT_ENTRY curEntry;
224 get_fat(&curEntry, fs->fat, cluster, fs);
225
226 data = fs->fat + cluster * 4;
227 offs = fs->fat_start + cluster * 4;
228 /* According to M$, the high 4 bits of a FAT32 entry are reserved and
229 * are not part of the cluster number. So we never touch them. */
Matt Mower18794c82015-11-11 16:22:45 -0600230 *(uint32_t *)data = htole32((new & 0xfffffff) |
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500231 (curEntry.reserved << 28));
232 size = 4;
233 }
234 break;
235 default:
236 die("Bad FAT entry size: %d bits.", fs->fat_bits);
237 }
238 fs_write(offs, size, data);
239 if (fs->nfats > 1) {
240 fs_write(offs + fs->fat_size, size, data);
241 }
242}
243
Matt Mower18794c82015-11-11 16:22:45 -0600244int bad_cluster(DOS_FS * fs, uint32_t cluster)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500245{
246 FAT_ENTRY curEntry;
247 get_fat(&curEntry, fs->fat, cluster, fs);
248
249 return FAT_IS_BAD(fs, curEntry.value);
250}
251
252/**
253 * Get the cluster to which the specified cluster is linked.
254 * If the linked cluster is marked bad, abort.
255 *
256 * @param[in] fs Information about the filesystem
257 * @param[in] cluster Cluster to follow
258 *
259 * @return -1 'cluster' is at the end of the chain
260 * @return Other values Next cluster in this chain
261 */
Matt Mower18794c82015-11-11 16:22:45 -0600262uint32_t next_cluster(DOS_FS * fs, uint32_t cluster)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500263{
Matt Mower18794c82015-11-11 16:22:45 -0600264 uint32_t value;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500265 FAT_ENTRY curEntry;
266
267 get_fat(&curEntry, fs->fat, cluster, fs);
268
269 value = curEntry.value;
270 if (FAT_IS_BAD(fs, value))
271 die("Internal error: next_cluster on bad cluster");
272 return FAT_IS_EOF(fs, value) ? -1 : value;
273}
274
Matt Mower18794c82015-11-11 16:22:45 -0600275loff_t cluster_start(DOS_FS * fs, uint32_t cluster)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500276{
277 return fs->data_start + ((loff_t) cluster -
Matt Mower18794c82015-11-11 16:22:45 -0600278 2) * (uint64_t)fs->cluster_size;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500279}
280
281/**
282 * Update internal bookkeeping to show that the specified cluster belongs
283 * to the specified dentry.
284 *
285 * @param[in,out] fs Information about the filesystem
286 * @param[in] cluster Cluster being assigned
287 * @param[in] owner Information on dentry that owns this cluster
288 * (may be NULL)
289 */
Matt Mower18794c82015-11-11 16:22:45 -0600290void set_owner(DOS_FS * fs, uint32_t cluster, DOS_FILE * owner)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500291{
292 if (fs->cluster_owner == NULL)
293 die("Internal error: attempt to set owner in non-existent table");
294
295 if (owner && fs->cluster_owner[cluster]
296 && (fs->cluster_owner[cluster] != owner))
297 die("Internal error: attempt to change file owner");
298 fs->cluster_owner[cluster] = owner;
299}
300
Matt Mower18794c82015-11-11 16:22:45 -0600301DOS_FILE *get_owner(DOS_FS * fs, uint32_t cluster)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500302{
303 if (fs->cluster_owner == NULL)
304 return NULL;
305 else
306 return fs->cluster_owner[cluster];
307}
308
309void fix_bad(DOS_FS * fs)
310{
Matt Mower18794c82015-11-11 16:22:45 -0600311 uint32_t i;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500312
313 if (verbose)
314 printf("Checking for bad clusters.\n");
315 for (i = 2; i < fs->clusters + 2; i++) {
316 FAT_ENTRY curEntry;
317 get_fat(&curEntry, fs->fat, i, fs);
318
319 if (!get_owner(fs, i) && !FAT_IS_BAD(fs, curEntry.value))
320 if (!fs_test(cluster_start(fs, i), fs->cluster_size)) {
Matt Mower18794c82015-11-11 16:22:45 -0600321 printf("Cluster %lu is unreadable.\n", (unsigned long)i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500322 set_fat(fs, i, -2);
323 }
324 }
325}
326
327void reclaim_free(DOS_FS * fs)
328{
329 int reclaimed;
Matt Mower18794c82015-11-11 16:22:45 -0600330 uint32_t i;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500331
332 if (verbose)
333 printf("Checking for unused clusters.\n");
334 reclaimed = 0;
335 for (i = 2; i < fs->clusters + 2; i++) {
336 FAT_ENTRY curEntry;
337 get_fat(&curEntry, fs->fat, i, fs);
338
339 if (!get_owner(fs, i) && curEntry.value &&
340 !FAT_IS_BAD(fs, curEntry.value)) {
341 set_fat(fs, i, 0);
342 reclaimed++;
343 }
344 }
345 if (reclaimed)
Matt Mower18794c82015-11-11 16:22:45 -0600346 printf("Reclaimed %d unused cluster%s (%llu bytes).\n", (int)reclaimed,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500347 reclaimed == 1 ? "" : "s",
348 (unsigned long long)reclaimed * fs->cluster_size);
349}
350
351/**
352 * Assign the specified owner to all orphan chains (except cycles).
353 * Break cross-links between orphan chains.
354 *
355 * @param[in,out] fs Information about the filesystem
356 * @param[in] owner dentry to be assigned ownership of orphans
357 * @param[in,out] num_refs For each orphan cluster [index], how many
358 * clusters link to it.
359 * @param[in] start_cluster Where to start scanning for orphans
360 */
Matt Mower18794c82015-11-11 16:22:45 -0600361static void tag_free(DOS_FS * fs, DOS_FILE * owner, uint32_t *num_refs,
362 uint32_t start_cluster)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500363{
364 int prev;
Matt Mower18794c82015-11-11 16:22:45 -0600365 uint32_t i, walk;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500366
367 if (start_cluster == 0)
368 start_cluster = 2;
369
370 for (i = start_cluster; i < fs->clusters + 2; i++) {
371 FAT_ENTRY curEntry;
372 get_fat(&curEntry, fs->fat, i, fs);
373
374 /* If the current entry is the head of an un-owned chain... */
375 if (curEntry.value && !FAT_IS_BAD(fs, curEntry.value) &&
376 !get_owner(fs, i) && !num_refs[i]) {
377 prev = 0;
378 /* Walk the chain, claiming ownership as we go */
379 for (walk = i; walk != -1; walk = next_cluster(fs, walk)) {
380 if (!get_owner(fs, walk)) {
381 set_owner(fs, walk, owner);
382 } else {
383 /* We've run into cross-links between orphaned chains,
384 * or a cycle with a tail.
385 * Terminate this orphan chain (break the link)
386 */
387 set_fat(fs, prev, -1);
388
389 /* This is not necessary because 'walk' is owned and thus
390 * will never become the head of a chain (the only case
391 * that would matter during reclaim to files).
392 * It's easier to decrement than to prove that it's
393 * unnecessary.
394 */
395 num_refs[walk]--;
396 break;
397 }
398 prev = walk;
399 }
400 }
401 }
402}
403
404/**
405 * Recover orphan chains to files, handling any cycles or cross-links.
406 *
407 * @param[in,out] fs Information about the filesystem
408 */
409void reclaim_file(DOS_FS * fs)
410{
411 DOS_FILE orphan;
412 int reclaimed, files;
413 int changed = 0;
Matt Mower18794c82015-11-11 16:22:45 -0600414 uint32_t i, next, walk;
415 uint32_t *num_refs = NULL; /* Only for orphaned clusters */
416 uint32_t total_num_clusters;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500417
418 if (verbose)
419 printf("Reclaiming unconnected clusters.\n");
420
421 total_num_clusters = fs->clusters + 2UL;
Matt Mower18794c82015-11-11 16:22:45 -0600422 num_refs = alloc(total_num_clusters * sizeof(uint32_t));
423 memset(num_refs, 0, (total_num_clusters * sizeof(uint32_t)));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500424
425 /* Guarantee that all orphan chains (except cycles) end cleanly
426 * with an end-of-chain mark.
427 */
428
429 for (i = 2; i < total_num_clusters; i++) {
430 FAT_ENTRY curEntry;
431 get_fat(&curEntry, fs->fat, i, fs);
432
433 next = curEntry.value;
434 if (!get_owner(fs, i) && next && next < fs->clusters + 2) {
435 /* Cluster is linked, but not owned (orphan) */
436 FAT_ENTRY nextEntry;
437 get_fat(&nextEntry, fs->fat, next, fs);
438
439 /* Mark it end-of-chain if it links into an owned cluster,
440 * a free cluster, or a bad cluster.
441 */
442 if (get_owner(fs, next) || !nextEntry.value ||
443 FAT_IS_BAD(fs, nextEntry.value))
444 set_fat(fs, i, -1);
445 else
446 num_refs[next]++;
447 }
448 }
449
450 /* Scan until all the orphans are accounted for,
451 * and all cycles and cross-links are broken
452 */
453 do {
454 tag_free(fs, &orphan, num_refs, changed);
455 changed = 0;
456
457 /* Any unaccounted-for orphans must be part of a cycle */
458 for (i = 2; i < total_num_clusters; i++) {
459 FAT_ENTRY curEntry;
460 get_fat(&curEntry, fs->fat, i, fs);
461
462 if (curEntry.value && !FAT_IS_BAD(fs, curEntry.value) &&
463 !get_owner(fs, i)) {
464 if (!num_refs[curEntry.value]--)
465 die("Internal error: num_refs going below zero");
466 set_fat(fs, i, -1);
467 changed = curEntry.value;
Matt Mower18794c82015-11-11 16:22:45 -0600468 printf("Broke cycle at cluster %lu in free chain.\n", (unsigned long)i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500469
470 /* If we've created a new chain head,
471 * tag_free() can claim it
472 */
473 if (num_refs[curEntry.value] == 0)
474 break;
475 }
476 }
477 }
478 while (changed);
479
480 /* Now we can start recovery */
481 files = reclaimed = 0;
482 for (i = 2; i < total_num_clusters; i++)
483 /* If this cluster is the head of an orphan chain... */
484 if (get_owner(fs, i) == &orphan && !num_refs[i]) {
485 DIR_ENT de;
486 loff_t offset;
487 files++;
Matt Mower18794c82015-11-11 16:22:45 -0600488 offset = alloc_rootdir_entry(fs, &de, "FSCK%04dREC");
489 de.start = htole16(i & 0xffff);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500490 if (fs->fat_bits == 32)
Matt Mower18794c82015-11-11 16:22:45 -0600491 de.starthi = htole16(i >> 16);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500492 for (walk = i; walk > 0 && walk != -1;
493 walk = next_cluster(fs, walk)) {
Matt Mower18794c82015-11-11 16:22:45 -0600494 de.size = htole32(le32toh(de.size) + fs->cluster_size);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500495 reclaimed++;
496 }
497 fs_write(offset, sizeof(DIR_ENT), &de);
498 }
499 if (reclaimed)
500 printf("Reclaimed %d unused cluster%s (%llu bytes) in %d chain%s.\n",
501 reclaimed, reclaimed == 1 ? "" : "s",
502 (unsigned long long)reclaimed * fs->cluster_size, files,
503 files == 1 ? "" : "s");
504
505 free(num_refs);
506}
507
Matt Mower18794c82015-11-11 16:22:45 -0600508uint32_t update_free(DOS_FS * fs)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500509{
Matt Mower18794c82015-11-11 16:22:45 -0600510 uint32_t i;
511 uint32_t free = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500512 int do_set = 0;
513
514 for (i = 2; i < fs->clusters + 2; i++) {
515 FAT_ENTRY curEntry;
516 get_fat(&curEntry, fs->fat, i, fs);
517
518 if (!get_owner(fs, i) && !FAT_IS_BAD(fs, curEntry.value))
519 ++free;
520 }
521
522 if (!fs->fsinfo_start)
523 return free;
524
525 if (verbose)
526 printf("Checking free cluster summary.\n");
527 if (fs->free_clusters != 0xFFFFFFFF) {
528 if (free != fs->free_clusters) {
529 printf("Free cluster summary wrong (%ld vs. really %ld)\n",
Matt Mower18794c82015-11-11 16:22:45 -0600530 (long)fs->free_clusters, (long)free);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500531 if (interactive)
532 printf("1) Correct\n2) Don't correct\n");
533 else
534 printf(" Auto-correcting.\n");
535 if (!interactive || get_key("12", "?") == '1')
536 do_set = 1;
537 }
538 } else {
Matt Mower18794c82015-11-11 16:22:45 -0600539 printf("Free cluster summary uninitialized (should be %ld)\n", (long)free);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500540 if (rw) {
541 if (interactive)
542 printf("1) Set it\n2) Leave it uninitialized\n");
543 else
544 printf(" Auto-setting.\n");
545 if (!interactive || get_key("12", "?") == '1')
546 do_set = 1;
547 }
548 }
549
550 if (do_set) {
Matt Mower18794c82015-11-11 16:22:45 -0600551 uint32_t le_free = htole32(free);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500552 fs->free_clusters = free;
553 fs_write(fs->fsinfo_start + offsetof(struct info_sector, free_clusters),
554 sizeof(le_free), &le_free);
555 }
556
557 return free;
558}