OSDN Git Service

Return non-zero code from fsck if errors were found.
[android-x86/external-exfat.git] / fsck / main.c
1 /*
2  *  main.c
3  *  exFAT file system checker.
4  *
5  *  Created by Andrew Nayenko on 02.09.09.
6  *  This software is distributed under the GNU General Public License 
7  *  version 3 or any later.
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <exfat.h>
13 #include <exfatfs.h>
14 #include <inttypes.h>
15
16 #define exfat_debug(format, ...)
17
18 #define MB (1024 * 1024)
19
20 #define BMAP_GET(bitmap, index) ((bitmap)[(index) / 8] & (1u << ((index) % 8)))
21
22 uint64_t files_count, directories_count;
23
24 static uint64_t bytes2mb(uint64_t bytes)
25 {
26         return (bytes + MB / 2) / MB;
27 }
28
29 static void sbck(const struct exfat* ef)
30 {
31         const uint32_t block_size = (1 << ef->sb->block_bits); /* in bytes */
32         const uint32_t cluster_size = CLUSTER_SIZE(*ef->sb); /* in bytes */
33         const uint64_t total = (uint64_t) le32_to_cpu(ef->sb->cluster_count) *
34                 cluster_size;
35
36 #if 0 /* low-level info */
37         printf("First block           %8"PRIu64"\n",
38                         le64_to_cpu(ef->sb->block_start));
39         printf("Blocks count          %8"PRIu64"\n",
40                         le64_to_cpu(ef->sb->block_count));
41         printf("FAT first block       %8u\n",
42                         le32_to_cpu(ef->sb->fat_block_start));
43         printf("FAT blocks count      %8u\n",
44                         le32_to_cpu(ef->sb->fat_block_count));
45         printf("First cluster block   %8u\n",
46                         le32_to_cpu(ef->sb->cluster_block_start));
47         printf("Clusters count        %8u\n",
48                         le32_to_cpu(ef->sb->cluster_count));
49         printf("First cluster of root %8u\n",
50                         le32_to_cpu(ef->sb->rootdir_cluster));
51 #endif
52         printf("Block size            %8u bytes\n", block_size);
53         printf("Cluster size          %8u bytes\n", cluster_size);
54         printf("Total space           %8"PRIu64" MB\n", bytes2mb(total));
55         printf("Used space            %8hhu%%\n", ef->sb->allocated_percent);
56 }
57
58 static void nodeck(struct exfat* ef, struct exfat_node* node)
59 {
60         const cluster_t cluster_size = CLUSTER_SIZE(*ef->sb);
61         cluster_t clusters = (node->size + cluster_size - 1) / cluster_size;
62         cluster_t c = node->start_cluster;
63         
64         while (clusters--)
65         {
66                 if (CLUSTER_INVALID(c))
67                 {
68                         char name[EXFAT_NAME_MAX + 1];
69
70                         exfat_get_name(node, name, EXFAT_NAME_MAX);
71                         exfat_error("file `%s' has invalid cluster", name);
72                         return;
73                 }
74                 if (BMAP_GET(ef->cmap.chunk, c - EXFAT_FIRST_DATA_CLUSTER) == 0)
75                 {
76                         char name[EXFAT_NAME_MAX + 1];
77
78                         exfat_get_name(node, name, EXFAT_NAME_MAX);
79                         exfat_error("cluster 0x%x of file `%s' is not allocated", c, name);
80                 }
81                 c = exfat_next_cluster(ef, node, c);
82         }
83 }
84
85 static void dirck(struct exfat* ef, const char* path)
86 {
87         struct exfat_node* parent;
88         struct exfat_node* node;
89         struct exfat_iterator it;
90         int rc;
91         char subpath[EXFAT_NAME_MAX + 1];
92
93         if (exfat_lookup(ef, &parent, path) != 0)
94                 exfat_bug("directory `%s' is not found", path);
95         if (!(parent->flags & EXFAT_ATTRIB_DIR))
96                 exfat_bug("`%s' is not a directory (0x%x)", path, parent->flags);
97
98         rc = exfat_opendir(ef, parent, &it);
99         if (rc != 0)
100         {
101                 exfat_put_node(ef, parent);
102                 exfat_error("failed to open directory `%s'", path);
103                 return;
104         }
105         while ((node = exfat_readdir(ef, &it)))
106         {
107                 strcpy(subpath, path);
108                 strcat(subpath, "/");
109                 exfat_get_name(node, subpath + strlen(subpath),
110                                 EXFAT_NAME_MAX - strlen(subpath));
111                 exfat_debug("%s: %s, %llu bytes, cluster %u", subpath,
112                                 IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
113                                 node->size, node->start_cluster);
114                 if (node->flags & EXFAT_ATTRIB_DIR)
115                 {
116                         directories_count++;
117                         dirck(ef, subpath);
118                 }
119                 else
120                         files_count++;
121                 nodeck(ef, node);
122                 exfat_put_node(ef, node);
123         }
124         exfat_closedir(ef, &it);
125         exfat_put_node(ef, parent);
126 }
127
128 static void fsck(struct exfat* ef)
129 {
130         sbck(ef);
131         dirck(ef, "");
132 }
133
134 int main(int argc, char* argv[])
135 {
136         struct exfat ef;
137
138         if (argc != 2)
139         {
140                 fprintf(stderr, "usage: %s <spec>\n", argv[0]);
141                 return 1;
142         }
143         printf("exfatck %u.%u\n",
144                         EXFAT_VERSION_MAJOR, EXFAT_VERSION_MINOR);
145
146         if (exfat_mount(&ef, argv[1], "") != 0)
147                 return 1;
148
149         printf("Checking file system on %s.\n", argv[1]);
150         fsck(&ef);
151         exfat_unmount(&ef);
152         printf("Totally %"PRIu64" directories and %"PRIu64" files.\n",
153                         directories_count, files_count);
154
155         fputs("File system checking finished. ", stdout);
156         if (exfat_errors != 0)
157         {
158                 printf("ERRORS FOUND: %d.\n", exfat_errors);
159                 return 1;
160         }
161         puts("No errors found.");
162         return 0;
163 }