]> git.sven.stormbind.net Git - sven/exfatprogs.git/blob - fsck/repair.c
bbfb75d1397aa1128cb3212b43cf91073edf4ac7
[sven/exfatprogs.git] / fsck / repair.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  *  Copyright (C) 2020 Hyunchul Lee <hyc.lee@gmail.com>
4  */
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "exfat_ondisk.h"
9 #include "libexfat.h"
10 #include "fsck.h"
11 #include "repair.h"
12
13 struct exfat_repair_problem {
14         er_problem_code_t       prcode;
15         const char              *description;
16         bool (*fix_problem)(struct exfat *exfat,
17                         union exfat_repair_context *rctx);
18 };
19
20 static bool fix_bs_checksum(struct exfat *exfat,
21                         union exfat_repair_context *rctx)
22 {
23         unsigned int size;
24         unsigned int i;
25
26         size = EXFAT_SECTOR_SIZE(exfat->bs);
27         for (i = 0; i < size/sizeof(__le32); i++) {
28                 ((__le32 *)rctx->bs_checksum.checksum_sect)[i] =
29                                 rctx->bs_checksum.checksum;
30         }
31
32         if (exfat_write(exfat->blk_dev->dev_fd,
33                         rctx->bs_checksum.checksum_sect,
34                         size, size * 11) != size) {
35                 exfat_err("failed to write checksum sector\n");
36                 return false;
37         }
38
39         return true;
40 }
41
42 static struct exfat_repair_problem problems[] = {
43         {ER_BS_CHECKSUM,
44                 "the checksum of boot sector is not correct",
45                 fix_bs_checksum},
46 };
47
48 static struct exfat_repair_problem *find_problem(er_problem_code_t prcode)
49 {
50         unsigned int i;
51
52         for (i = 0; i < sizeof(problems)/sizeof(problems[0]); i++) {
53                 if (problems[i].prcode == prcode) {
54                         return &problems[i];
55                 }
56         }
57         return NULL;
58 }
59
60 static bool ask_repair(struct exfat *exfat, struct exfat_repair_problem *pr)
61 {
62         char answer[8];
63
64         switch (exfat->options & FSCK_OPTS_REPAIR) {
65         case FSCK_OPTS_REPAIR_ASK:
66                 do {
67                         printf("%s: Fix (y/N)?", pr->description);
68                         fflush(stdout);
69
70                         if (fgets(answer, sizeof(answer), stdin)) {
71                                 if (strcasecmp(answer, "Y\n") == 0)
72                                         return true;
73                                 else if (strcasecmp(answer, "\n") == 0 ||
74                                         strcasecmp(answer, "N\n") == 0)
75                                         return false;
76                         }
77                 } while (1);
78                 return false;
79         case FSCK_OPTS_REPAIR_YES:
80                 return true;
81         case FSCK_OPTS_REPAIR_NO:
82         case 0:
83         default:
84                 return false;
85         }
86         return false;
87 }
88
89 bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode,
90                         union exfat_repair_context *rctx)
91 {
92         struct exfat_repair_problem *pr = NULL;
93         int need_repair;
94
95         need_repair = ask_repair(exfat, pr);
96         if (!need_repair)
97                 return false;
98
99         pr = find_problem(prcode);
100         if (!pr) {
101                 exfat_err("unknown problem code. %#x\n", prcode);
102                 return false;
103         }
104
105         return pr->fix_problem(exfat, rctx);
106 }