1 /* Copyright 1995-1999,2001-2003,2007,2009,2011 Alain Knaff.
2 * This file is part of mtools.
4 * Mtools is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Mtools is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
18 * Mark bad blocks on disk
22 #include "sysincludes.h"
30 static void usage(int ret) NORETURN;
31 static void usage(int ret)
33 fprintf(stderr, "Mtools version %s, dated %s\n",
35 fprintf(stderr, "Usage: %s: [-c clusterList] [-s sectorList] [-c] [-V] device\n",
40 static void checkListTwice(char *filename) {
41 if(filename != NULL) {
42 fprintf(stderr, "Only one of the -c or -s options may be given\n");
48 * Marks given cluster as bad, but prints error instead if cluster already used
50 static void mark(Fs_t *Fs, long offset, unsigned int badClus) {
51 unsigned int old = Fs->fat_decode((Fs_t*)Fs, offset);
53 fatEncode((Fs_t*)Fs, offset, badClus);
57 fprintf(stderr, "Cluster %ld already marked\n", offset);
59 fprintf(stderr, "Cluster %ld is busy\n", offset);
68 static void progress(unsigned int i, unsigned int total) {
70 fprintf(stderr, " \r%d/%d\r", i, total);
73 static int scan(Fs_t *Fs, Stream_t *dev,
74 long cluster, unsigned int badClus,
75 char *buffer, int write) {
81 if(Fs->fat_decode((Fs_t*)Fs, cluster))
82 /* cluster busy, or already marked */
84 start = (cluster - 2) * Fs->cluster_size + Fs->clus_start;
85 pos = sectorsToBytes((Stream_t*)Fs, start);
87 ret = force_write(dev, buffer, pos, in_len);
91 ret = force_read(dev, in_buf, pos, in_len);
96 for(i=0; i<in_len; i++)
97 if(in_buf[i] != buffer[i]) {
105 printf("Bad cluster %ld found\n", cluster);
106 fatEncode((Fs_t*)Fs, cluster, badClus);
112 void mbadblocks(int argc, char **argv, int type)
115 unsigned int startSector=2;
116 unsigned int endSector=0;
117 struct MainParam_t mp;
121 char *filename = NULL;
123 unsigned int badClus;
127 while ((c = getopt(argc, argv, "i:s:cwS:E:")) != EOF) {
130 set_cmd_line_image(optarg, 0);
133 checkListTwice(filename);
134 filename = strdup(optarg);
137 checkListTwice(filename);
138 filename = strdup(optarg);
142 startSector = atol(optarg);
145 endSector = atol(optarg);
157 if (argc != optind+1 ||
158 !argv[optind][0] || argv[optind][1] != ':' || argv[optind][2]) {
164 Dir = open_root_dir(argv[optind][0], O_RDWR, NULL);
166 fprintf(stderr,"%s: Cannot initialize drive\n", argv[0]);
170 Fs = (Fs_t *)GetFs(Dir);
171 in_len = Fs->cluster_size * Fs->sector_size;
172 in_buf = malloc(in_len);
180 pat_buf=malloc(in_len * N_PATTERN);
187 for(i=0; i < in_len * N_PATTERN; i++) {
188 pat_buf[i] = random();
191 for(i=0; i < Fs->clus_start; i++ ){
192 ret = READS(Fs->Next, in_buf,
193 sectorsToBytes((Stream_t*)Fs, i), Fs->sector_size);
195 perror("early error");
198 if(ret < (signed int) Fs->sector_size){
199 fprintf(stderr,"end of file in file_read\n");
206 badClus = Fs->last_fat + 1;
210 if(endSector > Fs->num_clus + 2 || endSector <= 0)
211 endSector = Fs->num_clus + 2;
216 FILE *f = fopen(filename, "r");
218 fprintf(stderr, "Could not open %s (%s)\n",
219 filename, strerror(errno));
223 while(fgets(line, sizeof(line), f)) {
224 char *ptr = line + strspn(line, " \t");
225 long offset = strtoul(ptr, 0, 0);
227 offset = (offset-Fs->clus_start)/Fs->cluster_size + 2;
229 fprintf(stderr, "Sector before start\n");
230 } else if(offset >= Fs->num_clus) {
231 fprintf(stderr, "Sector beyond end\n");
233 mark(Fs, offset, badClus);
243 in_len = Fs->cluster_size * Fs->sector_size;
246 for(i=startSector; i< endSector; i++){
249 progress(i, Fs->num_clus);
250 ret |= scan(Fs, dev, i, badClus,
251 pat_buf + in_len * (i % N_PATTERN),
255 /* Flush cache, so that we are sure we read the data
256 back from disk, rather than from the cache */
260 /* Read data back, and compare to pattern */
261 for(i=startSector; i< endSector; i++){
264 progress(i, Fs->num_clus);
265 ret |= scan(Fs, dev, i, badClus,
266 pat_buf + in_len * (i % N_PATTERN),
272 for(i=startSector; i< endSector; i++){
275 progress(i, Fs->num_clus);
276 ret |= scan(Fs, dev, i, badClus, NULL, 0);