releasing version 0.9.8-1
[sven/exfat-utils.git] / dump / main.c
1 /*
2         main.c (08.11.10)
3         Prints detailed information about exFAT volume.
4
5         Copyright (C) 2011, 2012  Andrew Nayenko
6
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 */
20
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <inttypes.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <exfat.h>
27
28 static void print_generic_info(const struct exfat_super_block* sb)
29 {
30         printf("Volume serial number      0x%08x\n",
31                         le32_to_cpu(sb->volume_serial));
32         printf("FS version                       %hhu.%hhu\n",
33                         sb->version.major, sb->version.minor);
34         printf("Sector size               %10u\n",
35                         SECTOR_SIZE(*sb));
36         printf("Cluster size              %10u\n",
37                         CLUSTER_SIZE(*sb));
38 }
39
40 static void print_sector_info(const struct exfat_super_block* sb)
41 {
42         printf("Sectors count             %10"PRIu64"\n",
43                         le64_to_cpu(sb->sector_count));
44 }
45
46 static void print_cluster_info(const struct exfat_super_block* sb)
47 {
48         printf("Clusters count            %10u\n",
49                         le32_to_cpu(sb->cluster_count));
50 }
51
52 static void print_other_info(const struct exfat_super_block* sb)
53 {
54         printf("First sector              %10"PRIu64"\n",
55                         le64_to_cpu(sb->sector_start));
56         printf("FAT first sector          %10u\n",
57                         le32_to_cpu(sb->fat_sector_start));
58         printf("FAT sectors count         %10u\n",
59                         le32_to_cpu(sb->fat_sector_count));
60         printf("First cluster sector      %10u\n",
61                         le32_to_cpu(sb->cluster_sector_start));
62         printf("Root directory cluster    %10u\n",
63                         le32_to_cpu(sb->rootdir_cluster));
64         printf("Volume state                  0x%04hx\n",
65                         le16_to_cpu(sb->volume_state));
66         printf("FATs count                %10hhu\n",
67                         sb->fat_count);
68         printf("Drive number                    0x%02hhx\n",
69                         sb->drive_no);
70         printf("Allocated space           %9hhu%%\n",
71                         sb->allocated_percent);
72 }
73
74 static int dump_sb(const char* spec)
75 {
76         struct exfat_dev* dev;
77         struct exfat_super_block sb;
78
79         dev = exfat_open(spec, 1);
80         if (dev == NULL)
81                 return 1;
82
83         if (exfat_read(dev, &sb, sizeof(struct exfat_super_block)) < 0)
84         {
85                 exfat_close(dev);
86                 exfat_error("failed to read from `%s'", spec);
87                 return 1;
88         }
89         if (memcmp(sb.oem_name, "EXFAT   ", sizeof(sb.oem_name)) != 0)
90         {
91                 exfat_close(dev);
92                 exfat_error("exFAT file system is not found on `%s'", spec);
93                 return 1;
94         }
95
96         print_generic_info(&sb);
97         print_sector_info(&sb);
98         print_cluster_info(&sb);
99         print_other_info(&sb);
100
101         exfat_close(dev);
102         return 0;
103 }
104
105 static void dump_sectors(struct exfat* ef)
106 {
107         off_t a = 0, b = 0;
108
109         printf("Used sectors ");
110         while (exfat_find_used_sectors(ef, &a, &b) == 0)
111                 printf(" %"PRIu64"-%"PRIu64, a, b);
112         puts("");
113 }
114
115 static int dump_full(const char* spec, int used_sectors)
116 {
117         struct exfat ef;
118         uint32_t free_clusters;
119         uint64_t free_sectors;
120
121         if (exfat_mount(&ef, spec, "ro") != 0)
122                 return 1;
123
124         free_clusters = exfat_count_free_clusters(&ef);
125         free_sectors = (uint64_t) free_clusters << ef.sb->spc_bits;
126
127         printf("Volume label         %15s\n", exfat_get_label(&ef));
128         print_generic_info(ef.sb);
129         print_sector_info(ef.sb);
130         printf("Free sectors              %10"PRIu64"\n", free_sectors);
131         print_cluster_info(ef.sb);
132         printf("Free clusters             %10u\n", free_clusters);
133         print_other_info(ef.sb);
134         if (used_sectors)
135                 dump_sectors(&ef);
136
137         exfat_unmount(&ef);
138         return 0;
139 }
140
141 static void usage(const char* prog)
142 {
143         fprintf(stderr, "Usage: %s [-s] [-u] [-v] <device>\n", prog);
144         exit(1);
145 }
146
147 int main(int argc, char* argv[])
148 {
149         char** pp;
150         const char* spec = NULL;
151         int sb_only = 0;
152         int used_sectors = 0;
153
154         printf("dumpexfat %u.%u.%u\n",
155                         EXFAT_VERSION_MAJOR, EXFAT_VERSION_MINOR, EXFAT_VERSION_PATCH);
156
157         for (pp = argv + 1; *pp; pp++)
158         {
159                 if (strcmp(*pp, "-s") == 0)
160                         sb_only = 1;
161                 else if (strcmp(*pp, "-u") == 0)
162                         used_sectors = 1;
163                 else if (strcmp(*pp, "-v") == 0)
164                 {
165                         puts("Copyright (C) 2011, 2012  Andrew Nayenko");
166                         return 0;
167                 }
168                 else if (spec == NULL)
169                         spec = *pp;
170                 else
171                         usage(argv[0]);
172         }
173         if (spec == NULL)
174                 usage(argv[0]);
175
176         if (sb_only)
177                 return dump_sb(spec);
178
179         return dump_full(spec, used_sectors);
180 }