1/*  Copyright 1999,2001,2002,2009 Alain Knaff.
2 *  This file is part of mtools.
3 *
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.
8 *
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.
13 *
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/>.
16 *
17 * Test program for doctoring the fat
18 */
19
20
21#define LOWERCASE
22
23#include "sysincludes.h"
24#include "msdos.h"
25#include "mtools.h"
26#include "vfat.h"
27#include "mainloop.h"
28#include "plain_io.h"
29#include "nameclash.h"
30#include "file.h"
31#include "fs.h"
32#include "fsP.h"
33
34typedef struct Arg_t {
35	char *target;
36	MainParam_t mp;
37	ClashHandling_t ch;
38	Stream_t *sourcefile;
39	unsigned long fat;
40	int markbad;
41	int setsize;
42	unsigned long size;
43	Fs_t *Fs;
44} Arg_t;
45
46static int dos_doctorfat(direntry_t *entry, MainParam_t *mp)
47{
48	Fs_t *Fs = getFs(mp->File);
49	Arg_t *arg=(Arg_t *) mp->arg;
50
51	if(!arg->markbad && entry->entry != -3) {
52		/* if not root directory, change it */
53		set_word(entry->dir.start, arg->fat & 0xffff);
54		set_word(entry->dir.startHi, arg->fat >> 16);
55		if(arg->setsize)
56			set_dword(entry->dir.size, arg->size);
57		dir_write(entry);
58	}
59	arg->Fs = Fs;
60	return GOT_ONE;
61}
62
63static int unix_doctorfat(MainParam_t *mp)
64{
65	fprintf(stderr,"File does not reside on a Dos fs\n");
66	return ERROR_ONE;
67}
68
69static void usage(int ret) NORETURN;
70static void usage(int ret)
71{
72	fprintf(stderr,
73		"Mtools version %s, dated %s\n", mversion, mdate);
74	fprintf(stderr,
75		"Usage: [-b] %s file fat\n", progname);
76	exit(ret);
77}
78
79void mdoctorfat(int argc, char **argv, int mtype)
80{
81	Arg_t arg;
82	int c, ret;
83	long address, begin, end;
84	char *number, *eptr;
85	int i, j;
86	long offset;
87
88	/* get command line options */
89
90	init_clash_handling(& arg.ch);
91
92	offset = 0;
93
94	arg.markbad = 0;
95	arg.setsize = 0;
96
97	/* get command line options */
98	if(helpFlag(argc, argv))
99		usage(0);
100	while ((c = getopt(argc, argv, "i:bo:s:h")) != EOF) {
101		switch (c) {
102			case 'i':
103				set_cmd_line_image(optarg, 0);
104				break;
105			case 'b':
106				arg.markbad = 1;
107				break;
108			case 'o':
109				offset = strtoul(optarg,0,0);
110				break;
111			case 's':
112				arg.setsize=1;
113				arg.size = strtoul(optarg,0,0);
114				break;
115			case 'h':
116				usage(0);
117			case '?':
118				usage(1);
119				break;
120		}
121	}
122
123	if (argc - optind < 2)
124		usage(1);
125
126
127	/* only 1 file to copy... */
128	init_mp(&arg.mp);
129	arg.mp.arg = (void *) &arg;
130
131	arg.mp.callback = dos_doctorfat;
132	arg.mp.unixcallback = unix_doctorfat;
133
134	arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN;
135	arg.mp.openflags = O_RDWR;
136	arg.fat = strtoul(argv[optind+1], 0, 0) + offset;
137	ret=main_loop(&arg.mp, argv + optind, 1);
138	if(ret)
139		exit(ret);
140	address = 0;
141	for(i=optind+1; i < argc; i++) {
142		number = argv[i];
143		if (*number == '<') {
144			number++;
145		}
146		begin = strtoul(number, &eptr, 0);
147		if (eptr && *eptr == '-') {
148			number = eptr+1;
149			end = strtoul(number, &eptr, 0);
150		} else {
151			end = begin;
152		}
153		if (eptr == number) {
154			fprintf(stderr, "Not a number: %s\n", number);
155			exit(-1);
156		}
157
158		if (eptr && *eptr == '>') {
159			eptr++;
160		}
161		if (eptr && *eptr) {
162			fprintf(stderr, "Not a number: %s\n", eptr);
163			exit(-1);
164		}
165
166		for (j=begin; j <= end; j++) {
167			if(arg.markbad) {
168				arg.Fs->fat_encode(arg.Fs, j+offset, arg.Fs->last_fat ^ 6 ^ 8);
169			} else {
170				if(address) {
171					arg.Fs->fat_encode(arg.Fs, address, j+offset);
172				}
173				address = j+offset;
174			}
175		}
176	}
177
178	if (address && !arg.markbad) {
179		arg.Fs->fat_encode(arg.Fs, address, arg.Fs->end_fat);
180	}
181
182	exit(ret);
183}
184