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"
28 static void usage(int ret) NORETURN;
29 static void usage(int ret)
31 fprintf(stderr, "Mtools version %s, dated %s\n",
33 fprintf(stderr, "Usage: %s: [-c clusterList] [-s sectorList] [-c] [-V] device\n",
38 static void checkListTwice(char *filename) {
39 if(filename != NULL) {
40 fprintf(stderr, "Only one of the -c or -s options may be given\n");
46 * Marks given cluster as bad, but prints error instead if cluster already used
48 static void mark(Fs_t *Fs, uint32_t offset, uint32_t badClus) {
49 uint32_t old = Fs->fat_decode((Fs_t*)Fs, offset);
51 fatEncode((Fs_t*)Fs, offset, badClus);
55 fprintf(stderr, "Cluster %d already marked\n", offset);
57 fprintf(stderr, "Cluster %d is busy\n", offset);
66 static void progress(unsigned int i, unsigned int total) {
68 fprintf(stderr, " \r%d/%d\r", i, total);
71 static int scan(Fs_t *Fs, Stream_t *dev,
72 uint32_t cluster, uint32_t badClus,
73 char *buffer, int doWrite) {
79 if(Fs->fat_decode((Fs_t*)Fs, cluster))
80 /* cluster busy, or already marked */
82 start = (cluster - 2) * Fs->cluster_size + Fs->clus_start;
83 pos = sectorsToBytes(Fs, start);
85 ret = force_pwrite(dev, buffer, pos, in_len);
86 if(ret < 0 || (size_t) ret < in_len )
89 ret = force_pread(dev, in_buf, pos, in_len);
90 if(ret < (off_t) in_len )
94 for(i=0; i<in_len; i++)
95 if(in_buf[i] != buffer[i]) {
103 printf("Bad cluster %d found\n", cluster);
104 fatEncode((Fs_t*)Fs, cluster, badClus);
110 void mbadblocks(int argc, char **argv, int type UNUSEDP) NORETURN;
111 void mbadblocks(int argc, char **argv, int type UNUSEDP)
114 unsigned int startSector=2;
115 unsigned int endSector=0;
119 char *filename = NULL;
121 unsigned int badClus;
125 while ((c = getopt(argc, argv, "i:s:cwS:E:")) != EOF) {
128 set_cmd_line_image(optarg);
131 checkListTwice(filename);
132 filename = strdup(optarg);
135 checkListTwice(filename);
136 filename = strdup(optarg);
140 startSector = atoui(optarg);
143 endSector = atoui(optarg);
155 if (argc != optind+1 ||
156 !argv[optind][0] || argv[optind][1] != ':' || argv[optind][2]) {
160 Dir = open_root_dir(argv[optind][0], O_RDWR, NULL);
162 fprintf(stderr,"%s: Cannot initialize drive\n", argv[0]);
166 Fs = (Fs_t *)GetFs(Dir);
167 in_len = Fs->cluster_size * Fs->sector_size;
168 in_buf = malloc(in_len);
175 pat_buf=malloc(in_len * N_PATTERN);
182 for(i=0; i < in_len * N_PATTERN; i++) {
183 pat_buf[i] = (char) random();
186 for(i=0; i < Fs->clus_start; i++ ){
188 r = PREADS(Fs->head.Next, in_buf,
189 sectorsToBytes(Fs, i), Fs->sector_size);
191 perror("early error");
195 if((size_t) r < Fs->sector_size){
196 fprintf(stderr,"end of file in file_read\n");
203 badClus = Fs->last_fat + 1;
207 if(endSector > Fs->num_clus + 2 || endSector <= 0)
208 endSector = Fs->num_clus + 2;
213 FILE *f = fopen(filename, "r");
215 fprintf(stderr, "Could not open %s (%s)\n",
216 filename, strerror(errno));
220 while(fgets(line, sizeof(line), f)) {
221 char *ptr = line + strspn(line, " \t");
222 uint32_t offset = strtou32(ptr, 0, 0);
224 offset = (offset-Fs->clus_start)/Fs->cluster_size + 2;
226 fprintf(stderr, "Sector before start\n");
227 } else if(offset >= Fs->num_clus) {
228 fprintf(stderr, "Sector beyond end\n");
230 mark(Fs, offset, badClus);
240 in_len = Fs->cluster_size * Fs->sector_size;
243 for(i=startSector; i< endSector; i++){
246 progress(i, Fs->num_clus);
247 ret |= scan(Fs, dev, i, badClus,
248 pat_buf + in_len * (i % N_PATTERN),
252 /* Flush cache, so that we are sure we read the data
253 back from disk, rather than from the cache */
257 /* Read data back, and compare to pattern */
258 for(i=startSector; i< endSector; i++){
261 progress(i, Fs->num_clus);
262 ret |= scan(Fs, dev, i, badClus,
263 pat_buf + in_len * (i % N_PATTERN),
269 for(i=startSector; i< endSector; i++){
272 progress(i, Fs->num_clus);
273 ret |= scan(Fs, dev, i, badClus, NULL, 0);