dosfstools  4.2
About: dosfstools are utilities to create, check and label (MS-DOS) FAT filesystems.
  Fossies Dox: dosfstools-4.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

fat.c
Go to the documentation of this file.
1 /* 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>
5  Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
6  Copyright (C) 2021 Pali Roh├ír <pali.rohar@gmail.com>
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  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. If not, see <http://www.gnu.org/licenses/>.
20 
21  The complete text of the GNU General Public License
22  can be found in /usr/share/common-licenses/GPL-3 file.
23 */
24 
25 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
26  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include "common.h"
34 #include "fsck.fat.h"
35 #include "io.h"
36 #include "boot.h"
37 #include "check.h"
38 #include "fat.h"
39 
40 /**
41  * Fetch the FAT entry for a specified cluster.
42  *
43  * @param[out] entry Cluster to which cluster of interest is linked
44  * @param[in] fat FAT table for the partition
45  * @param[in] cluster Cluster of interest
46  * @param[in] fs Information from the FAT boot sectors (bits per FAT entry)
47  */
48 void get_fat(FAT_ENTRY * entry, void *fat, uint32_t cluster, DOS_FS * fs)
49 {
50  unsigned char *ptr;
51 
52  if (cluster > fs->data_clusters + 1) {
53  die("Internal error: cluster out of range in get_fat() (%lu > %lu).",
54  (unsigned long)cluster, (unsigned long)(fs->data_clusters + 1));
55  }
56 
57  switch (fs->fat_bits) {
58  case 12:
59  ptr = &((unsigned char *)fat)[cluster * 3 / 2];
60  entry->value = 0xfff & (cluster & 1 ? (ptr[0] >> 4) | (ptr[1] << 4) :
61  (ptr[0] | ptr[1] << 8));
62  break;
63  case 16:
64  entry->value = le16toh(((unsigned short *)fat)[cluster]);
65  break;
66  case 32:
67  /* According to M$, the high 4 bits of a FAT32 entry are reserved and
68  * are not part of the cluster number. So we cut them off. */
69  {
70  uint32_t e = le32toh(((unsigned int *)fat)[cluster]);
71  entry->value = e & 0xfffffff;
72  entry->reserved = e >> 28;
73  }
74  break;
75  default:
76  die("Bad FAT entry size: %d bits.", fs->fat_bits);
77  }
78 }
79 
80 void release_fat(DOS_FS * fs)
81 {
82  if (fs->fat)
83  free(fs->fat);
84  if (fs->cluster_owner)
85  free(fs->cluster_owner);
86  fs->fat = NULL;
87  fs->cluster_owner = NULL;
88 }
89 
90 static void fix_first_cluster(DOS_FS * fs, void * first_cluster)
91 {
92  struct boot_sector b;
93 
94  fs_read(0, sizeof(b), &b);
95 
96  printf("Fixing first cluster in FAT.\n");
97  if (fs->fat_bits == 12)
98  *(uint16_t *)first_cluster = htole16((le16toh(*(uint16_t *)first_cluster) & 0xf000) | FAT_EXTD(fs) | b.media);
99  else if (fs->fat_bits == 16)
100  *(uint16_t *)first_cluster = htole16(FAT_EXTD(fs) | b.media);
101  else
102  *(uint32_t *)first_cluster = htole32(FAT_EXTD(fs) | b.media);
103 }
104 
105 /**
106  * Build a bookkeeping structure from the partition's FAT table.
107  * If the partition has multiple FATs and they don't agree, try to pick a winner,
108  * and queue a command to overwrite the loser.
109  * One error that is fixed here is a cluster that links to something out of range.
110  *
111  * @param[inout] fs Information about the filesystem
112  * @param[in] mode 0 - read-only, 1 - read-write (no repair), 2 - repair
113  */
114 void read_fat(DOS_FS * fs, int mode)
115 {
116  int eff_size, alloc_size;
117  uint32_t i;
118  void *first, *second = NULL;
119  int first_ok, second_ok = 0;
120  FAT_ENTRY first_media, second_media;
121  uint32_t total_num_clusters;
122 
123  if (fat_table > fs->nfats)
124  die("Requested FAT table %ld does not exist.", fat_table);
125  if (fat_table > 2)
126  die("Reading FAT table greather than 2 is implemented yet.");
127 
128  /* Clean up from previous pass */
129  release_fat(fs);
130 
131  total_num_clusters = fs->data_clusters + 2;
132  eff_size = (total_num_clusters * fs->fat_bits + 7) / 8ULL;
133 
134  if (fs->fat_bits != 12)
135  alloc_size = eff_size;
136  else
137  /* round up to an even number of FAT entries to avoid special
138  * casing the last entry in get_fat() */
139  alloc_size = (total_num_clusters * 12 + 23) / 24 * 3;
140 
141  first = alloc(alloc_size);
142  fs_read(fs->fat_start, eff_size, first);
143  get_fat(&first_media, first, 0, fs);
144  first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
145  if (fs->nfats > 1) {
146  second = alloc(alloc_size);
147  fs_read(fs->fat_start + fs->fat_size, eff_size, second);
148  get_fat(&second_media, second, 0, fs);
149  second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
150  }
151  if (mode != 0 && fat_table == 0) {
152  if (!first_ok && second && !second_ok)
153  die("Both FATs appear to be corrupt. Giving up. Run fsck.fat with non-zero -F option.");
154  if (!first_ok && !second)
155  die("First FAT appears to be corrupt and second FAT does not exist. Giving up. Run fsck.fat with -F 1 option.");
156  }
157  if (mode == 0 && !first_ok && second && second_ok) {
158  /* In read-only mode if first FAT is corrupted and second is OK then use second FAT */
159  void *first_backup = first;
160  first = second;
161  second = first_backup;
162  }
163  if (mode != 0 && fat_table == 0 && second && memcmp(first, second, eff_size) != 0) {
164  if (mode != 2)
165  die("FATs differ, please run fsck.fat");
166  if (first_ok && !second_ok) {
167  printf("FATs differ - using first FAT.\n");
168  fs_write(fs->fat_start + fs->fat_size, eff_size, first);
169  } else if (!first_ok && second_ok) {
170  printf("FATs differ - using second FAT.\n");
171  fs_write(fs->fat_start, eff_size, second);
172  memcpy(first, second, eff_size);
173  } else {
174  if (first_ok && second_ok)
175  printf("FATs differ but appear to be intact.\n");
176  else
177  printf("FATs differ and both appear to be corrupt.\n");
178  if (get_choice(1, " Using first FAT.",
179  2,
180  1, "Use first FAT",
181  2, "Use second FAT") == 1) {
182  if (!first_ok) {
183  fix_first_cluster(fs, first);
184  fs_write(fs->fat_start, (fs->fat_bits + 7) / 8, first);
185  }
186  fs_write(fs->fat_start + fs->fat_size, eff_size, first);
187  } else {
188  if (!second_ok) {
189  fix_first_cluster(fs, second);
190  fs_write(fs->fat_start + fs->fat_size, (fs->fat_bits + 7) / 8, second);
191  }
192  fs_write(fs->fat_start, eff_size, second);
193  memcpy(first, second, eff_size);
194  }
195  }
196  }
197  if (mode != 0 && fat_table != 0) {
198  if (fat_table == 1) {
199  printf("Using first FAT.\n");
200  if (!first_ok) {
201  fix_first_cluster(fs, first);
202  fs_write(fs->fat_start, (fs->fat_bits + 7) / 8, first);
203  }
204  if (second && memcmp(first, second, eff_size) != 0)
205  fs_write(fs->fat_start + fs->fat_size, eff_size, first);
206  } else if (fat_table == 2) {
207  printf("Using second FAT.\n");
208  if (!second_ok) {
209  fix_first_cluster(fs, second);
210  fs_write(fs->fat_start + fs->fat_size, (fs->fat_bits + 7) / 8, second);
211  }
212  if (memcmp(first, second, eff_size) != 0) {
213  fs_write(fs->fat_start, eff_size, second);
214  memcpy(first, second, eff_size);
215  }
216  }
217  }
218  if (second) {
219  free(second);
220  }
221  fs->fat = (unsigned char *)first;
222 
223  fs->cluster_owner = alloc(total_num_clusters * sizeof(DOS_FILE *));
224  memset(fs->cluster_owner, 0, (total_num_clusters * sizeof(DOS_FILE *)));
225 
226  if (mode == 0)
227  return;
228 
229  /* Truncate any cluster chains that link to something out of range */
230  for (i = 2; i < fs->data_clusters + 2; i++) {
231  FAT_ENTRY curEntry;
232  get_fat(&curEntry, fs->fat, i, fs);
233  if (curEntry.value == 1) {
234  if (mode != 2)
235  die("Cluster %ld out of range (1), please run fsck.fat",
236  (long)(i - 2));
237  printf("Cluster %ld out of range (1). Setting to EOF.\n",
238  (long)(i - 2));
239  set_fat(fs, i, -1);
240  }
241  if (curEntry.value >= fs->data_clusters + 2 &&
242  (curEntry.value < FAT_MIN_BAD(fs))) {
243  if (mode != 2)
244  die("Cluster %ld out of range (%ld > %ld), please run fsck.fat",
245  (long)(i - 2), (long)curEntry.value,
246  (long)(fs->data_clusters + 2 - 1));
247  printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
248  (long)(i - 2), (long)curEntry.value,
249  (long)(fs->data_clusters + 2 - 1));
250  set_fat(fs, i, -1);
251  }
252  }
253 }
254 
255 /**
256  * Update the FAT entry for a specified cluster
257  * (i.e., change the cluster it links to).
258  * Queue a command to write out this change.
259  *
260  * @param[in,out] fs Information about the filesystem
261  * @param[in] cluster Cluster to change
262  * @param[in] new Cluster to link to
263  * Special values:
264  * 0 == free cluster
265  * -1 == end-of-chain
266  * -2 == bad cluster
267  */
268 void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new)
269 {
270  unsigned char *data = NULL;
271  int size;
272  off_t offs;
273 
274  if (cluster > fs->data_clusters + 1) {
275  die("Internal error: cluster out of range in set_fat() (%lu > %lu).",
276  (unsigned long)cluster, (unsigned long)(fs->data_clusters + 1));
277  }
278 
279  if (new == -1)
280  new = FAT_EOF(fs);
281  else if ((long)new == -2)
282  new = FAT_BAD(fs);
283  else if (new > fs->data_clusters + 1) {
284  die("Internal error: new cluster out of range in set_fat() (%lu > %lu).",
285  (unsigned long)new, (unsigned long)(fs->data_clusters + 1));
286  }
287 
288  switch (fs->fat_bits) {
289  case 12:
290  data = fs->fat + cluster * 3 / 2;
291  offs = fs->fat_start + cluster * 3 / 2;
292  if (cluster & 1) {
293  FAT_ENTRY prevEntry;
294  get_fat(&prevEntry, fs->fat, cluster - 1, fs);
295  data[0] = ((new & 0xf) << 4) | (prevEntry.value >> 8);
296  data[1] = new >> 4;
297  } else {
298  FAT_ENTRY subseqEntry;
299  if (cluster != fs->data_clusters + 1)
300  get_fat(&subseqEntry, fs->fat, cluster + 1, fs);
301  else
302  subseqEntry.value = 0;
303  data[0] = new & 0xff;
304  data[1] = (new >> 8) | ((0xff & subseqEntry.value) << 4);
305  }
306  size = 2;
307  break;
308  case 16:
309  data = fs->fat + cluster * 2;
310  offs = fs->fat_start + cluster * 2;
311  *(unsigned short *)data = htole16(new);
312  size = 2;
313  break;
314  case 32:
315  {
316  FAT_ENTRY curEntry;
317  get_fat(&curEntry, fs->fat, cluster, fs);
318 
319  data = fs->fat + cluster * 4;
320  offs = fs->fat_start + cluster * 4;
321  /* According to M$, the high 4 bits of a FAT32 entry are reserved and
322  * are not part of the cluster number. So we never touch them. */
323  *(uint32_t *)data = htole32((new & 0xfffffff) |
324  (curEntry.reserved << 28));
325  size = 4;
326  }
327  break;
328  default:
329  die("Bad FAT entry size: %d bits.", fs->fat_bits);
330  }
331  fs_write(offs, size, data);
332  if (fs->nfats > 1) {
333  fs_write(offs + fs->fat_size, size, data);
334  }
335 }
336 
337 int bad_cluster(DOS_FS * fs, uint32_t cluster)
338 {
339  FAT_ENTRY curEntry;
340  get_fat(&curEntry, fs->fat, cluster, fs);
341 
342  return FAT_IS_BAD(fs, curEntry.value);
343 }
344 
345 /**
346  * Get the cluster to which the specified cluster is linked.
347  * If the linked cluster is marked bad, abort.
348  *
349  * @param[in] fs Information about the filesystem
350  * @param[in] cluster Cluster to follow
351  *
352  * @return -1 'cluster' is at the end of the chain
353  * @return Other values Next cluster in this chain
354  */
355 uint32_t next_cluster(DOS_FS * fs, uint32_t cluster)
356 {
357  uint32_t value;
358  FAT_ENTRY curEntry;
359 
360  get_fat(&curEntry, fs->fat, cluster, fs);
361 
362  value = curEntry.value;
363  if (FAT_IS_BAD(fs, value))
364  die("Internal error: next_cluster on bad cluster");
365  return FAT_IS_EOF(fs, value) ? -1 : value;
366 }
367 
368 off_t cluster_start(DOS_FS * fs, uint32_t cluster)
369 {
370  /* TODO: check overflow */
371  return fs->data_start + ((off_t)cluster - 2) * (unsigned long long)fs->cluster_size;
372 }
373 
374 /**
375  * Update internal bookkeeping to show that the specified cluster belongs
376  * to the specified dentry.
377  *
378  * @param[in,out] fs Information about the filesystem
379  * @param[in] cluster Cluster being assigned
380  * @param[in] owner Information on dentry that owns this cluster
381  * (may be NULL)
382  */
383 void set_owner(DOS_FS * fs, uint32_t cluster, DOS_FILE * owner)
384 {
385  if (fs->cluster_owner == NULL)
386  die("Internal error: attempt to set owner in non-existent table");
387 
388  if (owner && fs->cluster_owner[cluster]
389  && (fs->cluster_owner[cluster] != owner))
390  die("Internal error: attempt to change file owner");
391  fs->cluster_owner[cluster] = owner;
392 }
393 
394 DOS_FILE *get_owner(DOS_FS * fs, uint32_t cluster)
395 {
396  if (fs->cluster_owner == NULL)
397  return NULL;
398  else
399  return fs->cluster_owner[cluster];
400 }
401 
402 void fix_bad(DOS_FS * fs)
403 {
404  uint32_t i;
405 
406  if (verbose)
407  printf("Checking for bad clusters.\n");
408  for (i = 2; i < fs->data_clusters + 2; i++) {
409  FAT_ENTRY curEntry;
410  get_fat(&curEntry, fs->fat, i, fs);
411 
412  if (!get_owner(fs, i) && !FAT_IS_BAD(fs, curEntry.value))
413  if (!fs_test(cluster_start(fs, i), fs->cluster_size)) {
414  printf("Cluster %lu is unreadable.\n", (unsigned long)i);
415  set_fat(fs, i, -2);
416  }
417  }
418 }
419 
421 {
422  int reclaimed;
423  uint32_t i;
424 
425  if (verbose)
426  printf("Checking for unused clusters.\n");
427  reclaimed = 0;
428  for (i = 2; i < fs->data_clusters + 2; i++) {
429  FAT_ENTRY curEntry;
430  get_fat(&curEntry, fs->fat, i, fs);
431 
432  if (!get_owner(fs, i) && curEntry.value &&
433  !FAT_IS_BAD(fs, curEntry.value)) {
434  set_fat(fs, i, 0);
435  reclaimed++;
436  }
437  }
438  if (reclaimed)
439  printf("Reclaimed %d unused cluster%s (%llu bytes).\n", (int)reclaimed,
440  reclaimed == 1 ? "" : "s",
441  (unsigned long long)reclaimed * fs->cluster_size);
442 }
443 
444 /**
445  * Assign the specified owner to all orphan chains (except cycles).
446  * Break cross-links between orphan chains.
447  *
448  * @param[in,out] fs Information about the filesystem
449  * @param[in] owner dentry to be assigned ownership of orphans
450  * @param[in,out] num_refs For each orphan cluster [index], how many
451  * clusters link to it.
452  * @param[in] start_cluster Where to start scanning for orphans
453  */
454 static void tag_free(DOS_FS * fs, DOS_FILE * owner, uint32_t *num_refs,
455  uint32_t start_cluster)
456 {
457  int prev;
458  uint32_t i, walk;
459 
460  if (start_cluster == 0)
461  start_cluster = 2;
462 
463  for (i = start_cluster; i < fs->data_clusters + 2; i++) {
464  FAT_ENTRY curEntry;
465  get_fat(&curEntry, fs->fat, i, fs);
466 
467  /* If the current entry is the head of an un-owned chain... */
468  if (curEntry.value && !FAT_IS_BAD(fs, curEntry.value) &&
469  !get_owner(fs, i) && !num_refs[i]) {
470  prev = 0;
471  /* Walk the chain, claiming ownership as we go */
472  for (walk = i; walk != -1; walk = next_cluster(fs, walk)) {
473  if (!get_owner(fs, walk)) {
474  set_owner(fs, walk, owner);
475  } else {
476  /* We've run into cross-links between orphaned chains,
477  * or a cycle with a tail.
478  * Terminate this orphan chain (break the link)
479  */
480  set_fat(fs, prev, -1);
481 
482  /* This is not necessary because 'walk' is owned and thus
483  * will never become the head of a chain (the only case
484  * that would matter during reclaim to files).
485  * It's easier to decrement than to prove that it's
486  * unnecessary.
487  */
488  num_refs[walk]--;
489  break;
490  }
491  prev = walk;
492  }
493  }
494  }
495 }
496 
497 /**
498  * Recover orphan chains to files, handling any cycles or cross-links.
499  *
500  * @param[in,out] fs Information about the filesystem
501  */
503 {
504  DOS_FILE orphan;
505  int reclaimed, files;
506  int changed = 0;
507  uint32_t i, next, walk;
508  uint32_t *num_refs = NULL; /* Only for orphaned clusters */
509  uint32_t total_num_clusters;
510 
511  if (verbose)
512  printf("Reclaiming unconnected clusters.\n");
513 
514  total_num_clusters = fs->data_clusters + 2;
515  num_refs = alloc(total_num_clusters * sizeof(uint32_t));
516  memset(num_refs, 0, (total_num_clusters * sizeof(uint32_t)));
517 
518  /* Guarantee that all orphan chains (except cycles) end cleanly
519  * with an end-of-chain mark.
520  */
521 
522  for (i = 2; i < total_num_clusters; i++) {
523  FAT_ENTRY curEntry;
524  get_fat(&curEntry, fs->fat, i, fs);
525 
526  next = curEntry.value;
527  if (!get_owner(fs, i) && next && next < fs->data_clusters + 2) {
528  /* Cluster is linked, but not owned (orphan) */
529  FAT_ENTRY nextEntry;
530  get_fat(&nextEntry, fs->fat, next, fs);
531 
532  /* Mark it end-of-chain if it links into an owned cluster,
533  * a free cluster, or a bad cluster.
534  */
535  if (get_owner(fs, next) || !nextEntry.value ||
536  FAT_IS_BAD(fs, nextEntry.value))
537  set_fat(fs, i, -1);
538  else
539  num_refs[next]++;
540  }
541  }
542 
543  /* Scan until all the orphans are accounted for,
544  * and all cycles and cross-links are broken
545  */
546  do {
547  tag_free(fs, &orphan, num_refs, changed);
548  changed = 0;
549 
550  /* Any unaccounted-for orphans must be part of a cycle */
551  for (i = 2; i < total_num_clusters; i++) {
552  FAT_ENTRY curEntry;
553  get_fat(&curEntry, fs->fat, i, fs);
554 
555  if (curEntry.value && !FAT_IS_BAD(fs, curEntry.value) &&
556  !get_owner(fs, i)) {
557  if (!num_refs[curEntry.value]--)
558  die("Internal error: num_refs going below zero");
559  set_fat(fs, i, -1);
560  changed = curEntry.value;
561  printf("Broke cycle at cluster %lu in free chain.\n", (unsigned long)i);
562 
563  /* If we've created a new chain head,
564  * tag_free() can claim it
565  */
566  if (num_refs[curEntry.value] == 0)
567  break;
568  }
569  }
570  }
571  while (changed);
572 
573  /* Now we can start recovery */
574  files = reclaimed = 0;
575  for (i = 2; i < total_num_clusters; i++)
576  /* If this cluster is the head of an orphan chain... */
577  if (get_owner(fs, i) == &orphan && !num_refs[i]) {
578  DIR_ENT de;
579  off_t offset;
580  files++;
581  offset = alloc_rootdir_entry(fs, &de, "FSCK%04dREC", 1);
582  de.start = htole16(i & 0xffff);
583  if (fs->fat_bits == 32)
584  de.starthi = htole16(i >> 16);
585  for (walk = i; walk > 0 && walk != -1;
586  walk = next_cluster(fs, walk)) {
587  de.size = htole32(le32toh(de.size) + fs->cluster_size);
588  reclaimed++;
589  }
590  fs_write(offset, sizeof(DIR_ENT), &de);
591  }
592  if (reclaimed)
593  printf("Reclaimed %d unused cluster%s (%llu bytes) in %d chain%s.\n",
594  reclaimed, reclaimed == 1 ? "" : "s",
595  (unsigned long long)reclaimed * fs->cluster_size, files,
596  files == 1 ? "" : "s");
597 
598  free(num_refs);
599 }
600 
601 uint32_t update_free(DOS_FS * fs)
602 {
603  uint32_t i;
604  uint32_t free = 0;
605  int do_set = 0;
606 
607  for (i = 2; i < fs->data_clusters + 2; i++) {
608  FAT_ENTRY curEntry;
609  get_fat(&curEntry, fs->fat, i, fs);
610 
611  if (!get_owner(fs, i) && !FAT_IS_BAD(fs, curEntry.value))
612  ++free;
613  }
614 
615  if (!fs->fsinfo_start)
616  return free;
617 
618  if (verbose)
619  printf("Checking free cluster summary.\n");
620  if (fs->free_clusters != 0xFFFFFFFF) {
621  if (free != fs->free_clusters) {
622  printf("Free cluster summary wrong (%ld vs. really %ld)\n",
623  (long)fs->free_clusters, (long)free);
624  if (get_choice(1, " Auto-correcting.",
625  2,
626  1, "Correct",
627  2, "Don't correct") == 1)
628  do_set = 1;
629  }
630  } else {
631  printf("Free cluster summary uninitialized (should be %ld)\n", (long)free);
632  if (rw) {
633  if (get_choice(1, " Auto-setting.",
634  2,
635  1, "Set it",
636  2, "Leave it uninitialized") == 1)
637  do_set = 1;
638  }
639  }
640 
641  if (do_set) {
642  uint32_t le_free = htole32(free);
643  fs->free_clusters = free;
644  fs_write(fs->fsinfo_start + offsetof(struct info_sector, free_clusters),
645  sizeof(le_free), &le_free);
646  }
647 
648  return free;
649 }
off_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern, int gen_name)
Definition: boot.c:52
void die(const char *msg,...)
Definition: common.c:53
void * alloc(int size)
Definition: common.c:81
int get_choice(int noninteractive_result, const char *noninteractive_msg, int choices,...)
Definition: common.c:157
void fix_bad(DOS_FS *fs)
Definition: fat.c:402
void reclaim_free(DOS_FS *fs)
Definition: fat.c:420
uint32_t next_cluster(DOS_FS *fs, uint32_t cluster)
Definition: fat.c:355
void set_owner(DOS_FS *fs, uint32_t cluster, DOS_FILE *owner)
Definition: fat.c:383
void release_fat(DOS_FS *fs)
Definition: fat.c:80
int bad_cluster(DOS_FS *fs, uint32_t cluster)
Definition: fat.c:337
uint32_t update_free(DOS_FS *fs)
Definition: fat.c:601
void read_fat(DOS_FS *fs, int mode)
Definition: fat.c:114
off_t cluster_start(DOS_FS *fs, uint32_t cluster)
Definition: fat.c:368
static void tag_free(DOS_FS *fs, DOS_FILE *owner, uint32_t *num_refs, uint32_t start_cluster)
Definition: fat.c:454
DOS_FILE * get_owner(DOS_FS *fs, uint32_t cluster)
Definition: fat.c:394
static void fix_first_cluster(DOS_FS *fs, void *first_cluster)
Definition: fat.c:90
void get_fat(FAT_ENTRY *entry, void *fat, uint32_t cluster, DOS_FS *fs)
Definition: fat.c:48
void set_fat(DOS_FS *fs, uint32_t cluster, int32_t new)
Definition: fat.c:268
void reclaim_file(DOS_FS *fs)
Definition: fat.c:502
int verbose
Definition: fatlabel.c:49
int rw
Definition: fatlabel.c:49
long fat_table
Definition: fatlabel.c:50
#define FAT_MIN_BAD(fs)
Definition: fsck.fat.h:190
#define FAT_BAD(fs)
Definition: fsck.fat.h:188
#define FAT_EOF(fs)
Definition: fsck.fat.h:185
#define FAT_EXTD(fs)
Definition: fsck.fat.h:195
#define FAT_IS_BAD(fs, v)
Definition: fsck.fat.h:192
#define FAT_IS_EOF(fs, v)
Definition: fsck.fat.h:186
int fs_test(off_t pos, int size)
Definition: io.c:101
void fs_read(off_t pos, int size, void *data)
Definition: io.c:78
void fs_write(off_t pos, int size, void *data)
Definition: io.c:114
static unsigned char * fat
Definition: mkfs.fat.c:257
uint16_t start
Definition: fsck.fat.h:138
uint16_t starthi
Definition: fsck.fat.h:137
uint32_t size
Definition: fsck.fat.h:139
unsigned int fat_bits
Definition: fsck.fat.h:161
unsigned int cluster_size
Definition: fsck.fat.h:167
unsigned int fat_size
Definition: fsck.fat.h:160
off_t fsinfo_start
Definition: fsck.fat.h:169
int nfats
Definition: fsck.fat.h:158
DOS_FILE ** cluster_owner
Definition: fsck.fat.h:173
off_t fat_start
Definition: fsck.fat.h:159
uint32_t data_clusters
Definition: fsck.fat.h:168
unsigned char * fat
Definition: fsck.fat.h:172
off_t data_start
Definition: fsck.fat.h:166
long free_clusters
Definition: fsck.fat.h:170
Definition: fsck.fat.h:152
uint32_t value
Definition: fsck.fat.h:153
uint32_t reserved
Definition: fsck.fat.h:154
uint8_t media
Definition: fsck.fat.h:62