1/*  Copyright 1999-2003,2007,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 * mcat.c
18 * Same thing as cat /dev/fd0 or cat file >/dev/fd0
19 * Something, that isn't possible with floppyd anymore.
20 */
21
22#include "sysincludes.h"
23#include "msdos.h"
24#include "mtools.h"
25#include "mainloop.h"
26#include "fsP.h"
27#include "xdf_io.h"
28#include "floppyd_io.h"
29#include "plain_io.h"
30
31static void usage(void)
32{
33	fprintf(stderr, "Mtools version %s, dated %s\n",
34		mversion, mdate);
35	fprintf(stderr, "Usage: mcat [-V] [-w] device\n");
36	fprintf(stderr, "       -w write on device else read\n");
37	exit(1);
38}
39
40#ifdef __CYGWIN__
41#define BUF_SIZE 512
42#else
43#define BUF_SIZE 16000
44#endif
45
46static size_t bufLen(size_t blocksize, mt_size_t totalSize, mt_off_t address)
47{
48	if(totalSize == 0)
49		return blocksize;
50	if(address + blocksize > totalSize)
51		return totalSize - address;
52	return blocksize;
53}
54
55void mcat(int argc, char **argv, int type)
56{
57	struct device *dev;
58	struct device out_dev;
59	char drive, name[EXPAND_BUF];
60        char errmsg[200];
61        Stream_t *Stream;
62	char buf[BUF_SIZE];
63
64	mt_off_t address = 0;
65
66	char mode = O_RDONLY;
67	int optindex = 1;
68	size_t len;
69
70	noPrivileges = 1;
71
72	if (argc < 2) {
73		usage();
74	}
75
76	if (argv[1][0] == '-') {
77		if (argv[1][1] != 'w') {
78			usage();
79		}
80		mode = O_WRONLY;
81		optindex++;
82	}
83
84	if (argc - optindex < 1)
85		usage();
86
87
88	if (!argv[optindex][0] || argv[optindex][1] != ':'
89	    || argv[optindex][2]) {
90		usage();
91	}
92
93        drive = toupper(argv[optindex][0]);
94
95        /* check out a drive whose letter and parameters match */
96        sprintf(errmsg, "Drive '%c:' not supported", drive);
97        Stream = NULL;
98        for (dev=devices; dev->name; dev++) {
99                FREE(&Stream);
100                if (dev->drive != drive)
101                        continue;
102                out_dev = *dev;
103                expand(dev->name,name);
104#ifdef USING_NEW_VOLD
105                strcpy(name, getVoldName(dev, name));
106#endif
107
108                Stream = 0;
109#ifdef USE_XDF
110                Stream = XdfOpen(&out_dev, name, mode, errmsg, 0);
111				if(Stream)
112                        out_dev.use_2m = 0x7f;
113
114#endif
115
116#ifdef USE_FLOPPYD
117                if(!Stream)
118                        Stream = FloppydOpen(&out_dev, dev, name,
119					     mode, errmsg, 0, 1);
120#endif
121
122
123                if (!Stream)
124                        Stream = SimpleFileOpen(&out_dev, dev, name, mode,
125						errmsg, 0, 1, 0);
126
127                if( !Stream)
128                        continue;
129                break;
130        }
131
132        /* print error msg if needed */
133        if ( dev->drive == 0 ){
134                FREE(&Stream);
135                fprintf(stderr,"%s\n",errmsg);
136                exit(1);
137        }
138
139
140	if (mode == O_WRONLY) {
141		mt_size_t size=0;
142		size = out_dev.sectors * out_dev.heads * out_dev.tracks;
143		size *= 512;
144		while ((len = fread(buf, 1,
145				    bufLen(BUF_SIZE, size, address),
146				    stdin)) > 0) {
147			int r = WRITES(Stream, buf, address, len);
148			fprintf(stderr, "Wrote to %d\n", (int) address);
149			if(r < 0)
150				break;
151			address += len;
152		}
153	} else {
154		while ((len = READS(Stream, buf, address, BUF_SIZE)) > 0) {
155			fwrite(buf, 1, len, stdout);
156			address += len;
157		}
158	}
159
160	FREE(&Stream);
161	exit(0);
162}
163