OSDN Git Service

a8274b27f839ca62f0e728d10214e187af0e99e7
[android-x86/external-parted.git] / debug / clearfat / clearfat.c
1 /*
2     clear_fat - a tool to clear unused space (for testing purposes)
3     Copyright (C) 2000, 2007-2010 Free Software Foundation, Inc.
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <getopt.h>
26 #include "closeout.h"
27 #include "configmake.h"
28 #include "error.h"
29 #include "long-options.h"
30 #include "progname.h"
31 #include "xstrtol.h"
32
33 #include "../../libparted/fs/fat/fat.h"
34
35 #include <locale.h>
36
37 /* Take care of NLS matters.  */
38
39 #include "gettext.h"
40 #if ! ENABLE_NLS
41 # undef textdomain
42 # define textdomain(Domainname) /* empty */
43 # undef bindtextdomain
44 # define bindtextdomain(Domainname, Dirname) /* empty */
45 #endif
46
47 #undef _
48 #define _(msgid) gettext (msgid)
49
50 #ifndef DISCOVER_ONLY
51
52 /* The official name of this program (e.g., no `g' prefix).  */
53 #define PROGRAM_NAME "clearfat"
54
55 #define AUTHORS \
56   "<http://git.debian.org/?p=parted/parted.git;a=blob_plain;f=AUTHORS>"
57
58 static void
59 usage (int status)
60 {
61   if (status != EXIT_SUCCESS)
62     fprintf (stderr, _("Try `%s --help' for more information.\n"),
63              program_name);
64   else
65     {
66       printf (_("\
67 Usage: %s [OPTION]\n\
68   or:  %s DEVICE MINOR\n"), PROGRAM_NAME, PROGRAM_NAME);
69       fputs (_("\
70 Clear unused space on a FAT partition (a GNU Parted testing tool).\n\
71 \n\
72 "), stdout);
73       fputs (_("      --help     display this help and exit\n"), stdout);
74       fputs (_("      --version  output version information and exit\n"),
75              stdout);
76       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
77     }
78   exit (status);
79 }
80
81 #define CLEAR_BUFFER_SIZE               (1024 * 1024)
82 #define CLEAR_BUFFER_SECTORS            (CLEAR_BUFFER_SIZE/512)
83
84 static char buffer [CLEAR_BUFFER_SIZE];
85
86 /* generic clearing code ***************************************************/
87
88 static int
89 _clear_sectors (PedGeometry* geom, PedSector start, PedSector count)
90 {
91         PedSector               pos;
92         PedSector               to_go = count;
93
94         for (pos = start;
95              pos < start + count;
96              pos += CLEAR_BUFFER_SECTORS, to_go -= CLEAR_BUFFER_SECTORS) {
97                 if (!ped_geometry_write (geom, buffer, start,
98                                          PED_MIN (CLEAR_BUFFER_SECTORS, to_go)))
99                         return 0;
100         }
101
102         return 1;
103 }
104
105 static int
106 _clear_sector_range (PedGeometry* geom, PedSector start, PedSector end)
107 {
108         return _clear_sectors (geom, start, end - start + 1);
109 }
110
111 static int
112 _clear_sector (PedGeometry* geom, PedSector sector)
113 {
114         return _clear_sectors (geom, sector, 1);
115 }
116
117 static int
118 _clear_partial_sector (PedGeometry* geom, PedSector sector,
119                        int offset, int count)
120 {
121         if (!ped_geometry_read (geom, buffer, sector, 1))
122                 goto error;
123         memset (buffer + offset, 0, count);
124         if (!ped_geometry_write (geom, buffer, sector, 1))
125                 goto error;
126
127         memset (buffer, 0, 512);
128         return 1;
129
130 error:
131         memset (buffer, 0, 512);
132         return 0;
133 }
134
135 static int
136 _clear_partial_range (PedGeometry* geom, PedSector sector, int start, int end)
137 {
138         return _clear_partial_sector (geom, sector, start, end - start + 1);
139 }
140
141 static int
142 _clear_clusters (PedFileSystem* fs, FatCluster start, FatCluster count)
143 {
144         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
145         return _clear_sectors (fs->geom, fat_cluster_to_sector(fs, start),
146                                count * fs_info->cluster_sectors);
147 }
148
149 /* FAT code ******************************************************************/
150
151 static void
152 _clear_before_fat (PedFileSystem* fs)
153 {
154         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
155         PedSector       sector;
156
157         for (sector = 1; sector < fs_info->fat_offset; sector++) {
158                 if (sector == fs_info->info_sector_offset)
159                         continue;
160                 if (sector == fs_info->boot_sector_backup_offset)
161                         continue;
162                 _clear_sector (fs->geom, sector);
163         }
164 }
165
166 static int
167 _calc_fat_entry_offset (PedFileSystem* fs, FatCluster cluster)
168 {
169         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
170
171         switch (fs_info->fat_type) {
172                 case FAT_TYPE_FAT12:
173                         PED_ASSERT (0, (void) 0);
174                         break;
175
176                 case FAT_TYPE_FAT16:
177                         return cluster * 2;
178
179                 case FAT_TYPE_FAT32:
180                         return cluster * 4;
181         }
182         return 0;
183 }
184
185 static void
186 _clear_unused_fats (PedFileSystem* fs)
187 {
188         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
189         PedSector       table_start;
190         int             table_num;
191         int             last_active_offset;
192         PedSector       last_active_sector;
193         int             last_active_sector_offset;
194
195         last_active_offset
196                 = _calc_fat_entry_offset (fs, fs_info->fat->cluster_count);
197         last_active_sector = last_active_offset / 512;
198         last_active_sector_offset = last_active_offset % 512 + 4;
199
200         for (table_num = 0; table_num < fs_info->fat_table_count; table_num++) {
201                 table_start = fs_info->fat_offset
202                               + table_num * fs_info->fat_sectors;
203
204                 if (last_active_sector_offset < 512) {
205                         _clear_partial_range (
206                                 fs->geom,
207                                 table_start + last_active_sector,
208                                 last_active_sector_offset,
209                                 512);
210                 }
211
212                 if (last_active_sector < fs_info->fat_sectors - 2) {
213                         _clear_sector_range (
214                                 fs->geom,
215                                 table_start + last_active_sector + 1,
216                                 table_start + fs_info->fat_sectors - 1);
217                 }
218         }
219 }
220
221 static int
222 _clear_unused_clusters (PedFileSystem* fs)
223 {
224         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
225         FatCluster      cluster;
226         FatCluster      run_start = 0; /* shut gcc up! */
227         FatCluster      run_length = 0;
228
229         for (cluster = 2; cluster < fs_info->cluster_count + 2; cluster++) {
230                 if (fat_table_is_available (fs_info->fat, cluster)) {
231                         if (!run_length) {
232                                 run_start = cluster;
233                                 run_length = 1;
234                         } else {
235                                 run_length++;
236                         }
237                 } else {
238                         if (run_length)
239                                 _clear_clusters (fs, run_start, run_length);
240                         run_length = 0;
241                 }
242         }
243
244         if (run_length)
245                 _clear_clusters (fs, run_start, run_length);
246
247         return 1;
248 }
249
250 static void
251 _clear_unused_fat (PedFileSystem* fs)
252 {
253         memset (buffer, 0, CLEAR_BUFFER_SIZE);
254
255         _clear_before_fat (fs);
256         _clear_unused_fats (fs);
257         _clear_unused_clusters (fs);
258 }
259
260 /* bureaucracy ***************************************************************/
261
262 int
263 main (int argc, char* argv[])
264 {
265         PedDevice*              dev;
266         PedDisk*                disk;
267         PedPartition*           part;
268         PedFileSystem*          fs;
269
270         set_program_name (argv[0]);
271         setlocale (LC_ALL, "");
272         bindtextdomain (PACKAGE, LOCALEDIR);
273         textdomain (PACKAGE);
274
275         atexit (close_stdout);
276
277         parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION,
278                             usage, AUTHORS, (char const *) NULL);
279         if (getopt_long (argc, argv, "", NULL, NULL) != -1)
280           usage (EXIT_FAILURE);
281
282         if (argc - optind < 2)
283           {
284             error (0, 0, _("too few arguments"));
285             usage (EXIT_FAILURE);
286           }
287         if (2 < argc - optind)
288           {
289             error (0, 0, _("too many arguments"));
290             usage (EXIT_FAILURE);
291           }
292
293         unsigned long minor_dev_number;
294         if (xstrtoul (argv[2], NULL, 10, &minor_dev_number, NULL)
295             || INT_MAX < minor_dev_number)
296           {
297             error (0, 0, _("invalid minor device number: %s"), argv[2]);
298             usage (EXIT_FAILURE);
299           }
300
301         dev = ped_device_get (argv [1]);
302         if (!dev)
303                 goto error;
304         if (!ped_device_open (dev))
305                 goto error;
306
307         disk = ped_disk_new (dev);
308         if (!disk)
309                 goto error_close_dev;
310
311         part = ped_disk_get_partition (disk, minor_dev_number);
312         if (!part) {
313                 printf ("Couldn't find partition `%s'\n", argv[2]);
314                 goto error_destroy_disk;
315         }
316
317         fs = ped_file_system_open (&part->geom);
318         if (!fs)
319                 goto error_destroy_disk;
320
321         if (strncmp (fs->type->name, "fat", 3)) {
322                 printf ("Not a FAT file system!\n");
323                 goto error_close_fs;
324         }
325
326         _clear_unused_fat (fs);
327
328         ped_file_system_close (fs);
329         ped_disk_destroy (disk);
330         ped_device_close (dev);
331         return 0;
332
333 error_close_fs:
334         ped_file_system_close (fs);
335 error_destroy_disk:
336         ped_disk_destroy (disk);
337 error_close_dev:
338         ped_device_close (dev);
339 error:
340         return 1;
341 }
342
343 #else /* DISCOVER_ONLY */
344
345 /* hack! */
346 int
347 main()
348 {
349         printf ("You must compile libparted with full read/write support\n");
350         return 1;
351 }
352
353 #endif /* DISCOVER_ONLY */